自定义头像

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

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

以下为demo

AndroidManifest.xml


  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.example.testcam"
  4. android:versionCode="1"
  5. android:versionName="1.0" >
  6.  
  7. <uses-sdk
  8. android:minSdkVersion="18"
  9. android:targetSdkVersion="25" />
  10. <uses-permission android:name="android.permission.CAMERA"/>
  11. <!-- 写sd卡的权限 -->
  12. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  13. <!-- 读sd卡权限 -->
  14. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  15. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
  16. <application
  17. android:allowBackup="true"
  18. android:icon="@drawable/ic_launcher"
  19. android:label="@string/app_name"
  20. android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
  21. <activity
  22. android:name=".MainActivity"
  23. android:label="@string/app_name" >
  24. <intent-filter>
  25. <action android:name="android.intent.action.MAIN" />
  26. <category android:name="android.intent.category.LAUNCHER" />
  27. </intent-filter>
  28. </activity>
  29. <!-- 适配Android 7.0+ -->
  30. <!--
  31. name可以为FileProvider的子类
  32. authorities这个可以随便定义,只要不与其他程序冲突就行
  33. exported必须为false
  34. grantUriPermissions必须为true
  35. -->
  36. <provider
  37. android:name="android.support.v4.content.FileProvider"
  38. android:authorities="com.zwwx.ssss.filesprovider"
  39. android:exported="false"
  40. android:grantUriPermissions="true">
  41. <!-- 定义content://URI与真实file路径之间的映射关系(配在一个xml文件中) -->
  42. <meta-data
  43. android:name="android.support.FILE_PROVIDER_PATHS"
  44. android:resource="@xml/filepaths"/>
  45. </provider>
  46. <!-- end -->
  47. </application>
  48.  
  49. </manifest>


filepaths.xml


  1. <?xml version="1.0" encoding="utf-8"?>
  2. <paths xmlns:android="http://schemas.android.com/apk/res/android">
  3. <root-path name="root" path="" />
  4. <files-path name="files" path="" />
  5. <cache-path name="cache" path="" />
  6. <external-path name="external" path="" />
  7. <external-files-path name="name" path="path" />
  8. <external-cache-path name="name" path="path" />
  9. </paths>
9999.png


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

activity_main.xml


  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:paddingBottom="@dimen/activity_vertical_margin"
  6. android:paddingLeft="@dimen/activity_horizontal_margin"
  7. android:paddingRight="@dimen/activity_horizontal_margin"
  8. android:paddingTop="@dimen/activity_vertical_margin"
  9. android:orientation="vertical"
  10. tools:context="com.example.testphoto.MainActivity" >
  11.  
  12. <TextView
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content"
  15. android:text="@string/hello_world" />
  16.  
  17. <Button
  18. android:id="@+id/btnPick"
  19. android:layout_width="165px"
  20. android:layout_height="wrap_content"
  21. android:text="选择图片"/>
  22. <ImageView
  23. android:id="@+id/imgView"
  24. android:layout_width="wrap_content"
  25. android:layout_height="wrap_content"/>
  26. </LinearLayout>


MainActivity.java


  1. package com.example.testcam;
  2.  
  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. import java.io.FileNotFoundException;
  6. import java.io.FileOutputStream;
  7. import java.io.InputStream;
  8. import android.Manifest;
  9. import android.annotation.SuppressLint;
  10. import android.app.Activity;
  11. import android.content.ContentValues;
  12. import android.content.Intent;
  13. import android.content.pm.PackageManager;
  14. import android.graphics.Bitmap;
  15. import android.graphics.BitmapFactory;
  16. import android.net.Uri;
  17. import android.os.Build;
  18. import android.os.Bundle;
  19. import android.os.Environment;
  20. import android.os.StrictMode;
  21. import android.provider.MediaStore;
  22. import android.widget.Button;
  23. import android.widget.ImageView;
  24. import android.util.Log;
  25. import android.view.View;
  26. import android.support.v4.app.ActivityCompat;
  27. import android.support.v4.content.ContextCompat;
  28. import android.support.v4.content.FileProvider;
  29. /**
  30. * 上传头像功能demo
  31. * @author
  32. */
  33. public class MainActivity extends Activity {
  34. private static final int REQUEST_CODE_PICK_PHOTO = 1; //选择照片返回
  35. private static final int REQUEST_CODE_TAKE_PHOTO = 2; //拍照返回
  36. private static final int REQUEST_CODE_CUT_OK = 3; //编辑返回
  37. private int apiVersion;
  38. private Uri saveUri; //最终处理后的相片保存路径
  39. private Uri cameraSaveUri; //相机拍照保存路径
  40. private int clipWidth = 100;
  41. private int clipHeight = 100;
  42. private String clipFileName;
  43. private String cameraSaveFileName = "avatar_tmp.jpg";
  44. //对应AndroidManifest中provider的authorities
  45. private String authorities = "com.zwwx.ssss.filesprovider";
  46. @Override
  47. protected void onCreate(Bundle savedInstanceState) {
  48. super.onCreate(savedInstanceState);
  49. setContentView(R.layout.activity_main);
  50. apiVersion = android.os.Build.VERSION.SDK_INT;
  51. Button btnPick = (Button) findViewById(R.id.btnPick);
  52. btnPick.setOnClickListener(new View.OnClickListener(){
  53. @Override
  54. public void onClick(View v) {
  55. takePhoto(1, 80, 80, "avatar.jpg");
  56. }
  57. });
  58. /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
  59. debug("*** StrictMode");
  60. StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
  61. StrictMode.setVmPolicy(builder.build());
  62. }*/
  63. }
  64. //--begin
  65. // 内存紧张的手机启动拍照功能时活动可能会被系统销毁,当返回活动时需要自己处理数据重建。
  66. @Override
  67. public void onSaveInstanceState(Bundle outState) {
  68. debug("onSaveInstanceState()");
  69. outState.putString("savePath", getPhotoSavePath());
  70. outState.putInt("clipWidth", clipWidth);
  71. outState.putInt("clipHeight", clipHeight);
  72. outState.putString("clipFileName", clipFileName);
  73. super.onSaveInstanceState(outState);
  74. }
  75. @Override
  76. public void onRestoreInstanceState(Bundle savedInstanceState) {
  77. super.onRestoreInstanceState(savedInstanceState);
  78. debug("onRestoreInstanceState()");
  79. String savePath = savedInstanceState.getString("savePath");
  80. saveUri = Uri.parse(savePath);
  81. clipWidth = savedInstanceState.getInt("clipWidth");
  82. clipHeight = savedInstanceState.getInt("clipHeight");
  83. clipFileName = savedInstanceState.getString("clipFileName");
  84. }
  85. //--end
  86. public void takePhoto(int type, int clipWidth, int clipHeight, String clipFileName)
  87. {
  88. debug((String.format("takePhoto(clipWidth=%d, clipHeight=%d, clipFileName=%s)", clipWidth, clipHeight, clipFileName)));
  89. this.clipWidth = clipWidth;
  90. this.clipHeight = clipHeight;
  91. this.clipFileName = clipFileName;
  92. switch(type){
  93. case 1://相机
  94. if (checkPermissionCamera()) {
  95. openCamera();
  96. }
  97. break;
  98. case 2://相册
  99. openAlbum();
  100. break;
  101. }
  102. }
  103. /**
  104. * 检查权限
  105. * @return true有权限 false无权限
  106. */
  107. private Boolean checkPermissionCamera()
  108. {
  109. if (ContextCompat.checkSelfPermission(this,Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
  110. ContextCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
  111. ContextCompat.checkSelfPermission(this,Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
  112. ActivityCompat.requestPermissions(
  113. MainActivity.this,
  114. new String[]{
  115. Manifest.permission.CAMERA,
  116. Manifest.permission.WRITE_EXTERNAL_STORAGE,
  117. Manifest.permission.READ_EXTERNAL_STORAGE
  118. },
  119. REQUEST_CODE_TAKE_PHOTO);
  120. return false;
  121. }
  122. return true;
  123. }
  124. /**
  125. * 打开相机拍照
  126. */
  127. private void openCamera()
  128. {
  129. debug("Open Camera");
  130. debug("Android API Version: "+apiVersion);
  131. deleteSavedPhoto();
  132. deleteCameraSavedPhoto();
  133. File file = getCameraSaveFile();
  134. Uri uri = getUriForFile(file);
  135. Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  136. intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
  137. if (apiVersion >= Build.VERSION_CODES.N){//适配Android7.0+
  138. //临时授权允许其他程序访问本应用的Uri
  139. intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  140. }
  141.  
  142. startActivityForResult(intent, REQUEST_CODE_TAKE_PHOTO);
  143. }
  144.  
  145. /**
  146. * 打开本地相册
  147. */
  148. private void openAlbum()
  149. {
  150. debug("Open Album");
  151. deleteSavedPhoto();
  152. Intent i = new Intent(Intent.ACTION_PICK, null);
  153. i.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
  154. //设定结果返回
  155. startActivityForResult(i, REQUEST_CODE_PICK_PHOTO);
  156. }
  157. /**
  158. * 裁剪图片方法
  159. * @param uri
  160. */
  161. private void clipPhoto(Uri uri)
  162. {
  163. debug("load clip uri="+uri.toString());
  164. Intent intent = new Intent("com.android.camera.action.CROP");
  165. intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
  166. //可以选择图片类型,如果是*表明所有类型的图片
  167. intent.setDataAndType(uri, "image/*");
  168. // 下面这个crop = true是设置在开启的Intent中设置显示的VIEW可裁剪
  169. intent.putExtra("crop", "true");
  170. // aspectX aspectY 是宽高的比例,这里设置的是正方形(长宽比为1:1)
  171. intent.putExtra("aspectX", 1);
  172. intent.putExtra("aspectY", 1);
  173. // outputX outputY 是裁剪图片宽高
  174. intent.putExtra("outputX", clipWidth);
  175. intent.putExtra("outputY", clipHeight);
  176. //裁剪时是否保留图片的比例,这里的比例是1:1
  177. intent.putExtra("scale", true);
  178. intent.putExtra("scaleUpIfNeeded", true);
  179. //是否是圆形裁剪区域,设置了也不一定有效
  180. //intent.putExtra("circleCrop", true);
  181. //设置输出的格式
  182. if(clipFileName.endsWith(".jpg"))
  183. intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
  184. else
  185. intent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString());
  186. //是否将数据保留在Bitmap中返回(这种方式只适合返回小的裁剪图片,否则会内存占用过多导致闪退或卡死)
  187. //intent.putExtra("return-data", true);
  188. intent.putExtra("return-data", false);//部分手机需要明确设置为false
  189. //将裁剪图片直接保存到指定目录
  190. File file = getClipSaveFile();
  191. //注意:Android7.0+还是要用原来的Uri格式作为输出路径,不然会保存失败
  192. saveUri = Uri.fromFile(file);
  193. debug("save clip uri="+saveUri.toString());
  194. intent.putExtra(MediaStore.EXTRA_OUTPUT, saveUri);
  195. startActivityForResult(intent, REQUEST_CODE_CUT_OK);
  196. }
  197. @Override
  198. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  199. super.onActivityResult(requestCode, resultCode, data);
  200. debug("on activity result: requestCode="+requestCode+" resultCode="+resultCode);
  201. File file;
  202. Uri uri;
  203. switch(requestCode){
  204. case REQUEST_CODE_PICK_PHOTO://从相册选择照片后返回
  205. if(null != data){
  206. uri = data.getData();
  207. if(null != uri){//如果取消了选择这里返回null
  208. debug("return selected photo. uri="+uri.toString());
  209. clipPhoto(uri);
  210. }
  211. }
  212. break;
  213. case REQUEST_CODE_TAKE_PHOTO://拍照确认后返回
  214. file = getCameraSaveFile();
  215. debug("return camera photo. absolute path="+file.getAbsolutePath());
  216. debug("camera photo, exists="+file.exists());
  217. if(file.exists()){
  218. uri = getUriForFile(file);
  219. clipPhoto(uri);
  220. }else{
  221. debug("Error: camera photo not exists. absolute path="+file.getAbsolutePath());
  222. }
  223. break;
  224. case REQUEST_CODE_CUT_OK://裁剪编辑确认后返回
  225. file = getClipSaveFile();
  226. debug("return edit photo. absolute path="+file.getAbsolutePath());
  227. debug("edited photo, exists="+file.exists());
  228. if(file.exists())
  229. ShowSavedPhoto();
  230. break;
  231. }
  232. }
  233. //用户授权返回
  234. @Override
  235. public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
  236. {
  237. debug(String.format("onRequestPermissionsResult(requestCode=%d)", requestCode));
  238. switch(requestCode){
  239. case REQUEST_CODE_TAKE_PHOTO:
  240. if (null != permissions) {
  241. Boolean grant = true;
  242. for (int i=0; i<permissions.length; i++) {//检查所需权限是否都被授予
  243. if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
  244. grant = false;
  245. break;
  246. }
  247. }
  248. if (grant) {
  249. this.openCamera();
  250. }else{
  251. debug("permissions denied");
  252. }
  253. }
  254. break;
  255. }
  256. }
  257. //--- 文件路径--------
  258. private Uri getUriForFile(File file)
  259. {
  260. Uri uri;
  261. if (apiVersion < Build.VERSION_CODES.N){ //Android7.0之前
  262. uri = Uri.fromFile(file);
  263. }else{
  264. uri = FileProvider.getUriForFile(this, authorities, file);
  265. }
  266. return uri;
  267. }
  268. private String getPhotoSavePath()
  269. {
  270. return getPath(clipFileName, true);
  271. }
  272. private File getClipSaveFile()
  273. {
  274. File file = new File(getPath(clipFileName, false));
  275. return file;
  276. }
  277. private File getCameraSaveFile()
  278. {
  279. File file = new File(getPath(cameraSaveFileName, false));
  280. return file;
  281. }
  282. private String getPath(String fileName, Boolean filePrefix)
  283. {
  284. String path;
  285. if(filePrefix){
  286. path = "file:%s/"+fileName;
  287. }else{
  288. path = "%s/"+fileName;
  289. }
  290. Boolean sdcardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
  291. if(sdcardExist){
  292. path = String.format(path, this.getExternalFilesDir(""));
  293. }else{
  294. //Toast.makeText(this.mActivity, "SDCard not exist!", Toast.LENGTH_LONG).show();
  295. debug("SDCard not exist!");
  296. path = String.format(path, this.getFilesDir());
  297. }
  298. return path;
  299. }
  300. private void deleteSavedPhoto()
  301. {
  302. File file = new File(getPath(clipFileName, false));
  303. if(file.exists()){//发现用exists()时,文件路径不能有协议头.否则会一直返回false
  304. debug("save delete "+file.getPath());
  305. file.delete();
  306. }
  307. }
  308. private void deleteCameraSavedPhoto(){
  309. File file = new File(getPath(cameraSaveFileName, false));
  310. if(file.exists()){
  311. debug("camera delete "+file.getPath());
  312. file.delete();
  313. }
  314. }
  315. //--end
  316. private void ShowSavedPhoto()
  317. {
  318. try {
  319. Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(saveUri));
  320. ImageView imgView = (ImageView)findViewById(R.id.imgView);
  321. imgView.setImageBitmap(bitmap);
  322. } catch (FileNotFoundException e) {
  323. Log.e("zwwx", "read save photo failure! uri="+saveUri.toString());
  324. }
  325. }
  326. private void debug(String msg)
  327. {
  328. Log.d("zwwx", msg);
  329. }
  330. }


标签: Android

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号