自定义头像

作者:追风剑情 发布于:2018-1-29 15:16 分类:Android

让玩家通过从相册选择照片或拍照来制作自己的头像

以下为demo

AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testcam"
    android:versionCode="1"
    android:versionName="1.0" >

   <uses-sdk
        android:minSdkVersion="18"
        android:targetSdkVersion="25" />
    
    <uses-permission android:name="android.permission.CAMERA"/>
    <!-- 写sd卡的权限 -->
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
	<!-- 读sd卡权限 -->
	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
	<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    
 
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <!-- 适配Android 7.0+ -->
        <!-- 
        name可以为FileProvider的子类
        authorities这个可以随便定义,只要不与其他程序冲突就行
        exported必须为false
        grantUriPermissions必须为true
        -->
        <provider
	        android:name="android.support.v4.content.FileProvider"
	        android:authorities="com.zwwx.ssss.filesprovider"
	        android:exported="false"
	        android:grantUriPermissions="true">
            <!-- 定义content://URI与真实file路径之间的映射关系(配在一个xml文件中) -->
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths"/>
    	</provider>
    	<!-- end -->
    </application>

</manifest>


filepaths.xml


<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <root-path name="root" path="" />
    <files-path name="files" path="" />
    <cache-path name="cache" path="" />
    <external-path name="external" path="" />
    <external-files-path name="name" path="path" />
    <external-cache-path name="name" path="path" />
</paths>
9999.png


参见 https://www.jianshu.com/p/be817f3aa145

activity_main.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.testphoto.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

    <Button
        android:id="@+id/btnPick"
        android:layout_width="165px"
        android:layout_height="wrap_content"
        android:text="选择图片"/>
    
    <ImageView 
        android:id="@+id/imgView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>


MainActivity.java


package com.example.testcam;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
 
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.StrictMode;
import android.provider.MediaStore;
import android.widget.Button;
import android.widget.ImageView;
import android.util.Log;
import android.view.View;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
 
/**
 * 上传头像功能demo
 * @author 
 */
public class MainActivity extends Activity {
 
	private static final int REQUEST_CODE_PICK_PHOTO = 1; //选择照片返回
	private static final int REQUEST_CODE_TAKE_PHOTO = 2; //拍照返回
	private static final int REQUEST_CODE_CUT_OK = 3;	  //编辑返回
	
	private int apiVersion;
	private Uri saveUri; //最终处理后的相片保存路径
	private Uri cameraSaveUri; //相机拍照保存路径
	private int clipWidth = 100;
	private int clipHeight = 100;
	private String clipFileName;
	private String cameraSaveFileName = "avatar_tmp.jpg";
	
	//对应AndroidManifest中provider的authorities
	private String authorities = "com.zwwx.ssss.filesprovider";
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        apiVersion = android.os.Build.VERSION.SDK_INT;
        
        Button btnPick = (Button) findViewById(R.id.btnPick);
        btnPick.setOnClickListener(new View.OnClickListener(){
        	@Override
			public void onClick(View v) {
        		takePhoto(1, 80, 80, "avatar.jpg");
			}
        });
        
        /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        	debug("*** StrictMode");
            StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
            StrictMode.setVmPolicy(builder.build());
        }*/
    }
    
    //--begin
    // 内存紧张的手机启动拍照功能时活动可能会被系统销毁,当返回活动时需要自己处理数据重建。
    
    @Override
    public void onSaveInstanceState(Bundle outState) {
    	debug("onSaveInstanceState()");
        outState.putString("savePath", getPhotoSavePath());
        outState.putInt("clipWidth", clipWidth);
        outState.putInt("clipHeight", clipHeight);
        outState.putString("clipFileName", clipFileName);
        super.onSaveInstanceState(outState);
    }
    
    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
       super.onRestoreInstanceState(savedInstanceState);
       debug("onRestoreInstanceState()");
       String savePath = savedInstanceState.getString("savePath");
       saveUri = Uri.parse(savePath);
       clipWidth = savedInstanceState.getInt("clipWidth");
       clipHeight = savedInstanceState.getInt("clipHeight");
       clipFileName = savedInstanceState.getString("clipFileName");
    }
    //--end
 
    public void takePhoto(int type, int clipWidth, int clipHeight, String clipFileName)
    {
    	debug((String.format("takePhoto(clipWidth=%d, clipHeight=%d, clipFileName=%s)", clipWidth, clipHeight, clipFileName)));
    	
    	this.clipWidth = clipWidth;
    	this.clipHeight = clipHeight;
    	this.clipFileName = clipFileName;
    	
    	switch(type){
	    	case 1://相机
	    		if (checkPermissionCamera()) {
	    			openCamera();
	    		}
	    		break;
	    	case 2://相册
	    		openAlbum();
	    		break;
    	}
    }
    
    /**
     * 检查权限
     * @return true有权限  false无权限
     */
    private Boolean checkPermissionCamera()
    {
    	if (ContextCompat.checkSelfPermission(this,Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
    		ContextCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
    		ContextCompat.checkSelfPermission(this,Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    		ActivityCompat.requestPermissions(
        			MainActivity.this,
        			new String[]{
    					Manifest.permission.CAMERA,
    					Manifest.permission.WRITE_EXTERNAL_STORAGE,
    					Manifest.permission.READ_EXTERNAL_STORAGE
        			},
        			REQUEST_CODE_TAKE_PHOTO);
    		return false;
		}
    	return true;
    }
    
    /**
     * 打开相机拍照
     */
    private void openCamera()
    {
    	debug("Open Camera");
    	debug("Android API Version: "+apiVersion);
    	
    	deleteSavedPhoto();
    	deleteCameraSavedPhoto();
    	
    	File file = getCameraSaveFile();
    	Uri uri = getUriForFile(file);
    	
    	Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    	intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
    	if (apiVersion >= Build.VERSION_CODES.N){//适配Android7.0+
    		//临时授权允许其他程序访问本应用的Uri
    		intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    	}

        startActivityForResult(intent, REQUEST_CODE_TAKE_PHOTO);
    }

    /**
     * 打开本地相册
     */
    private void openAlbum()
    {    
    	debug("Open Album");
    	deleteSavedPhoto();
    	Intent i = new Intent(Intent.ACTION_PICK, null);
        i.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
        //设定结果返回
        startActivityForResult(i, REQUEST_CODE_PICK_PHOTO);
    }
    
    /**
     * 裁剪图片方法
     * @param uri
     */
    private void clipPhoto(Uri uri) 
    {
    	debug("load clip uri="+uri.toString());
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
        //可以选择图片类型,如果是*表明所有类型的图片
        intent.setDataAndType(uri, "image/*");
        // 下面这个crop = true是设置在开启的Intent中设置显示的VIEW可裁剪
        intent.putExtra("crop", "true");
        // aspectX aspectY 是宽高的比例,这里设置的是正方形(长宽比为1:1)
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        // outputX outputY 是裁剪图片宽高
        intent.putExtra("outputX", clipWidth);
        intent.putExtra("outputY", clipHeight);
        //裁剪时是否保留图片的比例,这里的比例是1:1
        intent.putExtra("scale", true);
        intent.putExtra("scaleUpIfNeeded", true);
        //是否是圆形裁剪区域,设置了也不一定有效
        //intent.putExtra("circleCrop", true);
        //设置输出的格式
        if(clipFileName.endsWith(".jpg"))
        	intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        else
        	intent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString());
        //是否将数据保留在Bitmap中返回(这种方式只适合返回小的裁剪图片,否则会内存占用过多导致闪退或卡死)
        //intent.putExtra("return-data", true);
        intent.putExtra("return-data", false);//部分手机需要明确设置为false
        
        //将裁剪图片直接保存到指定目录
        File file = getClipSaveFile();
        //注意:Android7.0+还是要用原来的Uri格式作为输出路径,不然会保存失败
        saveUri = Uri.fromFile(file);
        debug("save clip uri="+saveUri.toString());
        intent.putExtra(MediaStore.EXTRA_OUTPUT, saveUri);
 
        startActivityForResult(intent, REQUEST_CODE_CUT_OK);
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    	super.onActivityResult(requestCode, resultCode, data);
    	debug("on activity result: requestCode="+requestCode+" resultCode="+resultCode);
    	File file;
    	Uri uri;
    	switch(requestCode){
    		case REQUEST_CODE_PICK_PHOTO://从相册选择照片后返回
    			if(null != data){
    				uri = data.getData();
    				if(null != uri){//如果取消了选择这里返回null
	        			debug("return selected photo. uri="+uri.toString());
	        	    	clipPhoto(uri);
    				}
    			}
    	    	break;
    		case REQUEST_CODE_TAKE_PHOTO://拍照确认后返回
    			file = getCameraSaveFile();
    			debug("return camera photo. absolute path="+file.getAbsolutePath());
    			debug("camera photo, exists="+file.exists());
    			if(file.exists()){
    				uri = getUriForFile(file);
    				clipPhoto(uri);
    			}else{
    				debug("Error: camera photo not exists. absolute path="+file.getAbsolutePath());
    			}
    			break;
    		case REQUEST_CODE_CUT_OK://裁剪编辑确认后返回
    			file = getClipSaveFile();
    			debug("return edit photo. absolute path="+file.getAbsolutePath());
    			debug("edited photo, exists="+file.exists());
    			if(file.exists())
    				ShowSavedPhoto();
    			break;
    	}
    }
    
    //用户授权返回
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) 
    {
    	debug(String.format("onRequestPermissionsResult(requestCode=%d)", requestCode));
    	switch(requestCode){
    		case REQUEST_CODE_TAKE_PHOTO:
    			if (null != permissions) {
    				Boolean grant = true;
    				for (int i=0; i<permissions.length; i++) {//检查所需权限是否都被授予
    					if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
    						grant = false;
    						break;
    					}
    				}
    				if (grant) {
    					this.openCamera();
    				}else{
    					debug("permissions denied");
    				}
    			}
    			break;
    	}
    }
    
    //--- 文件路径--------
    private Uri getUriForFile(File file)
    {
    	Uri uri;
    	if (apiVersion < Build.VERSION_CODES.N){ //Android7.0之前
    		uri = Uri.fromFile(file);
    	}else{
    		uri = FileProvider.getUriForFile(this, authorities, file);
    	}
    	return uri;
    }
    
    private String getPhotoSavePath()
    {
    	return getPath(clipFileName, true);
    }
    
    private File getClipSaveFile()
    {
    	File file = new File(getPath(clipFileName, false));
    	return file;
    }
    
    private File getCameraSaveFile()
    {
    	File file = new File(getPath(cameraSaveFileName, false));
    	return file;
    }
    
    private String getPath(String fileName, Boolean filePrefix)
    {
    	String path;
    	if(filePrefix){
    		path = "file:%s/"+fileName;
    	}else{
    		path = "%s/"+fileName;
    	}
        Boolean sdcardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
        if(sdcardExist){
        	path = String.format(path, this.getExternalFilesDir(""));
        }else{
        	//Toast.makeText(this.mActivity, "SDCard not exist!", Toast.LENGTH_LONG).show();
        	debug("SDCard not exist!");
        	path = String.format(path, this.getFilesDir());
        }
    	return path;
    }
    
    private void deleteSavedPhoto()
    {
    	File file = new File(getPath(clipFileName, false));
    	if(file.exists()){//发现用exists()时,文件路径不能有协议头.否则会一直返回false
    		debug("save delete "+file.getPath());
    		file.delete();
    	}
    }
    
    private void deleteCameraSavedPhoto(){
    	File file = new File(getPath(cameraSaveFileName, false));
    	if(file.exists()){
    		debug("camera delete "+file.getPath());
    		file.delete();
    	}
    }
    //--end
    
    private void ShowSavedPhoto()
    {
    	try {
			Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(saveUri));
			ImageView imgView = (ImageView)findViewById(R.id.imgView);
			imgView.setImageBitmap(bitmap);
		} catch (FileNotFoundException e) {
			Log.e("zwwx", "read save photo failure! uri="+saveUri.toString());
		}
    }
    
    private void debug(String msg)
    {
    	Log.d("zwwx", msg);
    }
}


标签: Android

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号