自定义头像
作者:追风剑情 发布于: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>

参见 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
日历
最新文章
随机文章
热门文章
分类
存档
- 2025年3月(4)
- 2025年2月(3)
- 2025年1月(1)
- 2024年12月(5)
- 2024年11月(5)
- 2024年10月(5)
- 2024年9月(3)
- 2024年8月(3)
- 2024年7月(11)
- 2024年6月(3)
- 2024年5月(9)
- 2024年4月(10)
- 2024年3月(11)
- 2024年2月(24)
- 2024年1月(12)
- 2023年12月(3)
- 2023年11月(9)
- 2023年10月(7)
- 2023年9月(2)
- 2023年8月(7)
- 2023年7月(9)
- 2023年6月(6)
- 2023年5月(7)
- 2023年4月(11)
- 2023年3月(6)
- 2023年2月(11)
- 2023年1月(8)
- 2022年12月(2)
- 2022年11月(4)
- 2022年10月(10)
- 2022年9月(2)
- 2022年8月(13)
- 2022年7月(7)
- 2022年6月(11)
- 2022年5月(18)
- 2022年4月(29)
- 2022年3月(5)
- 2022年2月(6)
- 2022年1月(8)
- 2021年12月(5)
- 2021年11月(3)
- 2021年10月(4)
- 2021年9月(9)
- 2021年8月(14)
- 2021年7月(8)
- 2021年6月(5)
- 2021年5月(2)
- 2021年4月(3)
- 2021年3月(7)
- 2021年2月(2)
- 2021年1月(8)
- 2020年12月(7)
- 2020年11月(2)
- 2020年10月(6)
- 2020年9月(9)
- 2020年8月(10)
- 2020年7月(9)
- 2020年6月(18)
- 2020年5月(4)
- 2020年4月(25)
- 2020年3月(38)
- 2020年1月(21)
- 2019年12月(13)
- 2019年11月(29)
- 2019年10月(44)
- 2019年9月(17)
- 2019年8月(18)
- 2019年7月(25)
- 2019年6月(25)
- 2019年5月(17)
- 2019年4月(10)
- 2019年3月(36)
- 2019年2月(35)
- 2019年1月(28)
- 2018年12月(30)
- 2018年11月(22)
- 2018年10月(4)
- 2018年9月(7)
- 2018年8月(13)
- 2018年7月(13)
- 2018年6月(6)
- 2018年5月(5)
- 2018年4月(13)
- 2018年3月(5)
- 2018年2月(3)
- 2018年1月(8)
- 2017年12月(35)
- 2017年11月(17)
- 2017年10月(16)
- 2017年9月(17)
- 2017年8月(20)
- 2017年7月(34)
- 2017年6月(17)
- 2017年5月(15)
- 2017年4月(32)
- 2017年3月(8)
- 2017年2月(2)
- 2017年1月(5)
- 2016年12月(14)
- 2016年11月(26)
- 2016年10月(12)
- 2016年9月(25)
- 2016年8月(32)
- 2016年7月(14)
- 2016年6月(21)
- 2016年5月(17)
- 2016年4月(13)
- 2016年3月(8)
- 2016年2月(8)
- 2016年1月(18)
- 2015年12月(13)
- 2015年11月(15)
- 2015年10月(12)
- 2015年9月(18)
- 2015年8月(21)
- 2015年7月(35)
- 2015年6月(13)
- 2015年5月(9)
- 2015年4月(4)
- 2015年3月(5)
- 2015年2月(4)
- 2015年1月(13)
- 2014年12月(7)
- 2014年11月(5)
- 2014年10月(4)
- 2014年9月(8)
- 2014年8月(16)
- 2014年7月(26)
- 2014年6月(22)
- 2014年5月(28)
- 2014年4月(15)
友情链接
- Unity官网
- Unity圣典
- Unity在线手册
- Unity中文手册(圣典)
- Unity官方中文论坛
- Unity游戏蛮牛用户文档
- Unity下载存档
- Unity引擎源码下载
- Unity服务
- Unity Ads
- wiki.unity3d
- Visual Studio Code官网
- SenseAR开发文档
- MSDN
- C# 参考
- C# 编程指南
- .NET Framework类库
- .NET 文档
- .NET 开发
- WPF官方文档
- uLua
- xLua
- SharpZipLib
- Protobuf-net
- Protobuf.js
- OpenSSL
- OPEN CASCADE
- JSON
- MessagePack
- C在线工具
- 游戏蛮牛
- GreenVPN
- 聚合数据
- 热云
- 融云
- 腾讯云
- 腾讯开放平台
- 腾讯游戏服务
- 腾讯游戏开发者平台
- 腾讯课堂
- 微信开放平台
- 腾讯实时音视频
- 腾讯即时通信IM
- 微信公众平台技术文档
- 白鹭引擎官网
- 白鹭引擎开放平台
- 白鹭引擎开发文档
- FairyGUI编辑器
- PureMVC-TypeScript
- 讯飞开放平台
- 亲加通讯云
- Cygwin
- Mono开发者联盟
- Scut游戏服务器引擎
- KBEngine游戏服务器引擎
- Photon游戏服务器引擎
- 码云
- SharpSvn
- 腾讯bugly
- 4399原创平台
- 开源中国
- Firebase
- Firebase-Admob-Unity
- google-services-unity
- Firebase SDK for Unity
- Google-Firebase-SDK
- AppsFlyer SDK
- android-repository
- CQASO
- Facebook开发者平台
- gradle下载
- GradleBuildTool下载
- Android Developers
- Google中国开发者
- AndroidDevTools
- Android社区
- Android开发工具
- Google Play Games Services
- Google商店
- Google APIs for Android
- 金钱豹VPN
- TouchSense SDK
- MakeHuman
- Online RSA Key Converter
- Windows UWP应用
- Visual Studio For Unity
- Open CASCADE Technology
- 慕课网
- 阿里云服务器ECS
- 在线免费文字转语音系统
- AI Studio
- 网云穿
- 百度网盘开放平台
- 迅捷画图
- 菜鸟工具
- [CSDN] 程序员研修院
- 华为人脸识别
- 百度AR导航导览SDK
- 海康威视官网
- 海康开放平台
- 海康SDK下载
- git download
- Open CASCADE
- CascadeStudio
交流QQ群
-
Flash游戏设计: 86184192
Unity游戏设计: 171855449
游戏设计订阅号
