只用涉及到用户模块的App基本上就会用到头像替换的功能,类似的代码也是信手沾来,百度、GitHub以及各大论坛好博客一大把,随便粘过来就可以用了。但是。。。有坑。在华为荣耀手机上踩坑了,网上看了下问的人不少,没人回答。觉得很有必要写下来,希望能够帮到更多的朋友。

之前我也有写过一篇文章——Android图片上传(头像裁切+原图原样) ,被几个论坛转了不少,很是开心。

今天说的是这个坑,网上有一篇文章说出了问题——解决一下华为手机选取相册照片,选取不到问题,我在断点的时候也按照步骤发现就是这么回事:

笔者在选择了相册中的图片之后要进入图片裁剪的时候出错,(华为)手机提示“此图片无法获取”,经百度后,明白是版本不同导致的URI的问题的问题,原文如下:

4.3或以下,选了图片之后,根据Uri来做处理,很多帖子都有了,我就不详细说了.主要是4.4,如果使用上面pick的原生方法来选图,返回的uri还是正常的,但如果用ACTION_GET_CONTENT的方法,返回的uri跟4.3是完全不一样的,4.3返回的是带文件路径的,而4.4返回的却是content://com.android.providers.media.documents/document/image:3951这样的,没有路径,只有图片编号的uri.这就导致接下来无法根据图片路径来裁剪的步骤了.

既然知道了问题所在,那就用代码来说话了,注释里面该有的都有了,按照惯例需要的资源我会在文末给出0积分下载。

另外文中涉及的东西免费赠送:
1、圆形ImageView显示。
2、底部弹出框菜单。

看下效果图

点击头像弹出菜单


框选方形区域,这个界面和手机型号有关,不尽相同,这里是魅族手机的样式。


替换完成,圆形图片显示

package sun.geoffery.picselect;import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;import sun.geoffery.picselect.utils.SDCardUtils;
import sun.geoffery.picselect.view.BottomPushPopupWindow;
import sun.geoffery.picselect.view.CircleImageView;/*** 点击头像替换图片* 解决华为手机拍照和相册取不到图片的问题*/
public class MainActivity extends AppCompatActivity {private BottomPushPopupWindow mPop;public String TAG = "";private CircleImageView avatarImg;private static final String IMAGE_FILE_NAME = "head_image.jpg";// 头像文件/* 请求识别码 */private static final int CODE_GALLERY_REQUEST = 0xa0;//本地private static final int CODE_CAMERA_REQUEST = 0xa1;//拍照private static final int CODE_RESULT_REQUEST = 0xa2;//最终裁剪后的结果// 裁剪后图片的宽(X)和高(Y),480 X 480的正方形。private static int output_X = 480;private static int output_Y = 480;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);TAG = this.getClass().getName();avatarImg = (CircleImageView) findViewById(R.id.avatarImg);// 点击头像弹出菜单avatarImg.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {mPop = new BottomPopAvatar(MainActivity.this);mPop.show(MainActivity.this);}});}/*** 头像弹出框:拍照、相册、取消*/private class BottomPopAvatar extends BottomPushPopupWindow<Void> {public BottomPopAvatar(Context context) {super(context, null);}@Overrideprotected View generateCustomView(Void data) {View root = View.inflate(context, R.layout.layout_menu_2, null);TextView menuBtn1 = (TextView) root.findViewById(R.id.menuBtn1);TextView menuBtn2 = (TextView) root.findViewById(R.id.menuBtn2);menuBtn1.setText("拍照");menuBtn1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {dismiss();choseHeadImageFromCameraCapture();}});menuBtn2.setText("从相册选取");menuBtn2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {dismiss();choseHeadImageFromGallery();}});View cancelView = root.findViewById(R.id.cancel);cancelView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {dismiss();}});return root;}}// 启动手机相机拍摄照片作为头像private void choseHeadImageFromCameraCapture() {Intent intentFromCapture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);if (SDCardUtils.isSDCardEnable()) {// 判断存储卡是否可用,存储照片文件ContentValues values = new ContentValues();values.put(MediaStore.Images.Media.TITLE, IMAGE_FILE_NAME);intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/PicSelectDemo", IMAGE_FILE_NAME)));}startActivityForResult(intentFromCapture, CODE_CAMERA_REQUEST);}// 从本地相册选取图片作为头像private void choseHeadImageFromGallery() {Intent intentFromGallery = new Intent(Intent.ACTION_PICK, null);intentFromGallery.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");startActivityForResult(intentFromGallery, CODE_GALLERY_REQUEST);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent intent) {switch (requestCode) {case CODE_GALLERY_REQUEST://如果是来自本地的if (intent != null) {cropRawPhoto(intent.getData());//直接裁剪图片}break;case CODE_CAMERA_REQUEST:if (SDCardUtils.isSDCardEnable()) {File tempFile = new File(Environment.getExternalStorageDirectory() + "/PicSelectDemo", IMAGE_FILE_NAME);cropRawPhoto(Uri.fromFile(tempFile));} else {Toast.makeText(MainActivity.this, "没有SDCard!", Toast.LENGTH_LONG).show();}break;case CODE_RESULT_REQUEST:if (intent != null) {setImageToHeadView(intent);//设置图片框}break;}super.onActivityResult(requestCode, resultCode, intent);}/*** 裁剪原始的图片*/public void cropRawPhoto(Uri uri) {Intent intent = new Intent("com.android.camera.action.CROP");intent.setDataAndType(uri, "image/*");intent.putExtra("crop", "true");// aspectX aspectY 是宽高的比例intent.putExtra("aspectX", 1);intent.putExtra("aspectY", 1);// outputX outputY 是裁剪图片宽高intent.putExtra("outputX", output_X);intent.putExtra("outputY", output_Y);intent.putExtra("return-data", true);startActivityForResult(intent, CODE_RESULT_REQUEST);}/*** 提取保存裁剪之后的图片数据,并设置头像部分的View*/private void setImageToHeadView(Intent intent) {Bundle extras = intent.getExtras();if (extras != null) {Bitmap photo = extras.getParcelable("data");avatarImg.setImageBitmap(photo);//新建文件夹 先选好路径 再调用mkdir函数 现在是根目录下面的PicSelectDemo文件夹File nf = new File(Environment.getExternalStorageDirectory() + "/PicSelectDemo");nf.mkdir();//在根目录下面的PicSelectDemo文件夹下 创建head_image.jpg文件File f = new File(Environment.getExternalStorageDirectory() + "/PicSelectDemo", IMAGE_FILE_NAME);String path = f.getPath();// /data/data/com.datebao.jssapp/files/head_image.jpgLog.e(TAG, path);// TODO:需要上传服务器的图片路径FileOutputStream out = null;try {//打开输出流 将图片数据填入文件中out = new FileOutputStream(f);photo.compress(Bitmap.CompressFormat.PNG, 90, out);try {out.flush();out.close();} catch (IOException e) {e.printStackTrace();}} catch (FileNotFoundException e) {e.printStackTrace();}}}}

简单的页面布局文件activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center_horizontal"android:orientation="vertical"><sun.geoffery.picselect.view.CircleImageView
        android:id="@+id/avatarImg"android:layout_width="65dp"android:layout_height="65dp"android:layout_marginTop="30dp"android:src="@drawable/avatar" /><TextView
        android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:text="点击头像替换图片"android:textColor="@color/colorAccent"android:textSize="14sp" />
</LinearLayout>

另外除了主要的Activity代码,还涉及到了原型图片和弹出窗的样式文件

<?xml version="1.0" encoding="utf-8"?>
<resources><!-- 底部弹出窗 --><style name="Animations_BottomPush"><item name="android:windowEnterAnimation">@anim/pw_push_bottom_in</item><item name="android:windowExitAnimation">@anim/pw_push_bottom_out</item></style><!-- 圆形ImageView --><declare-styleable name="CircleImageView"><attr name="civ_border_width" format="dimension" /><attr name="civ_border_color" format="color" /><attr name="civ_border_overlay" format="boolean" /><attr name="civ_fill_color" format="color" /></declare-styleable>
</resources>

最后不要忘记在Manifest清单文件添加权限

<uses-feature
    android:name="android.hardware.camera"android:required="true" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.autofocus" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

另附两个动画文件:
pw_push_bottom_in.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" ><translate
        android:duration="@android:integer/config_shortAnimTime"android:fromYDelta="100%p"android:interpolator="@android:anim/accelerate_decelerate_interpolator"android:toYDelta="0" />
</set>

pw_push_bottom_out.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" ><translate
        android:duration="@android:integer/config_shortAnimTime"android:fromYDelta="0"android:interpolator="@android:anim/accelerate_decelerate_interpolator"android:toYDelta="100%p" />
</set>

最后给朋友们奉上完整的代码:源码下载(免积分放心下哦~)

遗留一个问题:
使用“Environment.getExternalStorageDirectory()”这个路径没问题,但是我想放到data/data下面使用“getApplicationContext().getFilesDir().getAbsolutePath()”就出问题,在魅族手机上拍照点击完成没反应,知道的朋友帮我在留言上处理一下,谢过。

欢迎留言帮我优化,谢谢。

Android 头像替换,解决华为手机取不到图片相关推荐

  1. Android自定义拍照解决部分手机拍完之后图片不清楚的问题

    昨天同事跟我说了一个bug,让我整了一天,从昨天下午这个时间到今天下午这个时间,哎... 大家都懂的 首先我来说一个bug,我用surfaceView来实现自定义拍照的功能,先来张在genymotio ...

  2. 解决android手机EditText设置光标颜色,android:textCursorDrawable=@drawable/corner_cursor 华为手机无效果的问题

    app开发,根据产品需求,需要修改输入框内,光标的颜色, 需要增加一个属性, android:textCursorDrawable="@drawable/corner_cursor" ...

  3. Android:解决华为手机隐藏虚拟按键Activity被重新创建的问题

    解决华为手机隐藏虚拟按键Activity被重新创建的问题 问题描述 解决方法 分析 问题描述 在华为手机P9上 屏幕底部虚拟按键用户可以随时隐藏或显示,在改变后 返回上一页,会导致页面重新创建,页面操 ...

  4. 【Android取证篇】华为手机OTG备份密码重置教程

    [Android取证篇]华为手机OTG备份密码重置教程 ​ 提取华为设备遇到OTG备份出来的数据信息软件无法正常解析时,排除数据提取不完整.软件设备等问题,可考虑重置华为的备份密码,重新备份数据再分析 ...

  5. 【Android取证篇】华为手机助手备份加密的版本

    [Android取证篇]华为手机助手备份加密的版本 ​ 在华为手机助手9.1.0.307及之后的版本,备份时会"强制加密",无法选择不加密备份.-[suy] 华为手机助手v9.1. ...

  6. Android微信登录在华为手机上无法调起授权界面的问题

    Android微信登录在华为手机上无法调起授权界面的问题 App集成了微信登录,在其他手机上微信登录都可以正常调起微信授权页面,并且登录成功,但是 在华为手机上调用微信登录,没报异常,也无法调起微信授 ...

  7. 华为手机怎么识别提取图片文字?APP一键识别

    平时我们用手机会接触到形形色色的图片文件,其中有一部分保存着咱们需要的文字信息.如果我们是华为手机怎么识别提取图片文字呢?给大伙介绍两种方式,有同样需求的小伙伴接着往下浏览吧. 1."智慧识 ...

  8. android华为获取相册,解决华为手机获取相册图片路径为null

    最近代码君遇到一个问题,在其他手机调用系统相册获取图片路径都是可以的,但是华为手机,执行相同代码,会报空指针异常,网上找了很多资料,都没什么实用的效果 Intent intent; intent = ...

  9. 华为手机android是什么意思,华为手机的英文文件夹是什么意思?哪些可以删除?今天总算知道了...

    原标题:华为手机的英文文件夹是什么意思?哪些可以删除?今天总算知道了 我们在使用华为手机的时候,经常会看到手机有各种各样的文件夹,那么你知道,这些各种各样的文件夹,都代表哪些意思吗?哪些才可以删掉呢? ...

最新文章

  1. 2021牛客寒假算法基础集训营1 题解
  2. 为什么正则化可以起到对模型容量进行控制_论文解读 | 基于正则化图神经网络的脑电情绪识别...
  3. python3打包exe_[求助]入坑学习python 需要装pyinstaller打包成exe
  4. 手把手教你:亲手打造Silverlight的Win8外观(1) 前言
  5. java ftpclient quit_一步一步android(6):关于FtpClient类的学习
  6. Leetcode之路径总和II
  7. vue.js视频教程,vue.js视频教程下载
  8. 《统计自然语言处理》(宗成庆)学习笔记(一)
  9. java商城源码(servlet,springboot,html,vue,uniapp,小程序,android)一套任意组合
  10. 【论文解读】关于深度森林的一点理解
  11. IIS:CS0016: 未能写入输出文件
  12. Perl_Tkx_Canvas绘图功能函数介绍
  13. 这8个要点,能让你的网页首图抓住用户注意力
  14. 想知道香港汇丰银行如何开户吗?
  15. Cocos2d游戏开发之如何解包获得pvr.ccz中的美术资源
  16. 阿里的人工智能之路 与谷歌亚马逊还有多大差距
  17. 视频达人批量解析功能
  18. 新员工入职表_员工培训
  19. 计算机维护维修是干啥的,什么是计算机维护
  20. 省市区json格式数据 下

热门文章

  1. graphviz.backend.ExecutableNotFound: failed to execute ‘dot‘Python使用Graphviz绘图报错解决
  2. linux基本操作及shell编程使用和vim
  3. 数学牛人们的轶事[上]--zt (出处不详)
  4. nn.BatchNorm1d
  5. 1129-2019-算法-普里姆算法(最小生成树MST-Prim算法)
  6. 电脑双击EASYBCD无法打开
  7. max模型修改小技巧(一)
  8. Java学习之八皇后
  9. SQL 增删改查(详细)
  10. 【华为云技术分享】自动驾驶网络系列四:我们谈自动驾驶网络到底在谈什么?