PopupWindow全屏显示以及适配不同手机屏幕之 应用实例 更换头像,拍照,相册选取附带动画效果
2017-03-06 23:57
841 查看
最近找工作,所以闲余时间还是比较充足的,今晚刚好没有睡意,抽取了一个之前项目中自己写过的一个功能。更换头像,可以拍照,可以从相册选取照片,有裁剪功能。其中的一个坑是PopupWindow的显示位置以及是否全屏显示适配不同手机。
话不多少,先上效果。
![](http://img.blog.csdn.net/20170306233207527?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzQ0NzE3MzY=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20170306233227783?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzQ0NzE3MzY=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
因为这个效果展示时间比较长,所以分了两段录结果还是大了,把gif图片质量压缩了。
大致解释下,效果就是点击按钮弹出popupwindow,更换头像可选择拍照和相册选取,并且可以裁剪。退出程序保存的头像依然保留。
下来先看看一步一步实现
由于今天我的Android studio有点,所以这个demo我是用eclipse写的。效果都是一样的。
1.PopupWindow 首先是布局样式 activity_choose_picture.xml
这个就是弹出popupwindow的布局
资源文件,style.xml这里我们要自定义样式
还有两个动画xml文件 push_bottom_in.xml
push_bottom_out.xml
需要注意的是这两个文件是建在anim目录下的,否则不起作用。
下来主要看MainActivity中的代码,
代码我注释写的比较详细,就直接看吧
这里有几点需要注意下,1,showAsDropDown(mGoneView);这个方法,是控制popupwindow显示位置的,参数我们可以理解为一个相对参照物,它是指// 弹出的PopupWindow左上角正对mGoneView的左下角显示。难怪之前没有设置的时候怎么调宽高都不是全屏显示的。这里的mGoneView是在activity_main.xml的最上面画一条线长宽为0,状态是gone。
2,mPopupWindow = new PopupWindow(mpopview, width, height - dip2px(50)
+ getStatusBarHeight());// 设置布局在屏幕中显示的位置,并且获取焦点
这行代码主要看第三个参数。其实测试发现Android系统有的PopupWindow计算高度的时候没有计算状态栏的高度,导致不能全屏。getStatusBarHeight()方法是获取状态栏高度的,至于这个为什么要减去dip2px(50)也不是很懂,他是一个把dp转化为px的一个方法。如果不减去则有的手机下面的“取消”会看不见。
之前将照片保存在手机中,以后每当打开程序它会从sd卡中读取之前保存的头像照片,并且设置显示,如果没有的话,则默认显示ic_launcher。
今天时间有点晚了,就不在细说了,稍后我会附上
话不多少,先上效果。
因为这个效果展示时间比较长,所以分了两段录结果还是大了,把gif图片质量压缩了。
大致解释下,效果就是点击按钮弹出popupwindow,更换头像可选择拍照和相册选取,并且可以裁剪。退出程序保存的头像依然保留。
下来先看看一步一步实现
由于今天我的Android studio有点,所以这个demo我是用eclipse写的。效果都是一样的。
1.PopupWindow 首先是布局样式 activity_choose_picture.xml
<RelativeLayout 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:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_margin="10dp" android:background="@color/btn_bottom_tv_gray" android:orientation="vertical" > <Button android:id="@+id/button_take_photo" style="@style/txt_camera_pop_menu" android:layout_width="match_parent" android:layout_height="45dp" android:background="@drawable/pop_first_selector" android:text="@string/camera_pop_camera" android:textSize="18sp" /> <Button android:id="@+id/button_choice_photo" style="@style/txt_camera_pop_menu" android:layout_width="match_parent" android:layout_height="45dp" android:background="@drawable/pop_last_selector" android:text="@string/camera_pop_album" android:textSize="18sp" /> <Button android:id="@+id/button_choice_cancel" style="@style/txt_camera_pop_menu" android:layout_width="match_parent" android:layout_height="45dp" android:layout_marginTop="10dp" android:background="@drawable/pop_single_selector" android:text="@string/camera_pop_cancel" android:textSize="18sp" /> </LinearLayout> </RelativeLayout>
这个就是弹出popupwindow的布局
资源文件,style.xml这里我们要自定义样式
<!-- Application theme. --> <style name="AppTheme" parent="AppBaseTheme"> <!-- All customizations that are NOT specific to a particular API-level can go here. --> <item name="android:windowNoTitle">true</item> </style> <style name="PopupAnimation" parent="android:Animation"> <item name="android:windowEnterAnimation">@anim/push_bottom_in</item> <item name="android:windowExitAnimation">@anim/push_bottom_out</item> </style> <style name="txt_camera_pop_menu"> <!-- PopupWindow左右弹出的效果 --> <item name="android:textColor">@color/camera_pop_normal</item> <item name="android:textSize">16sp</item> <item name="android:paddingTop">10dp</item> <item name="android:paddingBottom">10dp</item> <item name="android:gravity">center</item> </style>
还有两个动画xml文件 push_bottom_in.xml
<?xml version="1.0" encoding="utf-8"?> <!-- 上下滑入式 --> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="1000" android:fromYDelta="100%p" android:toYDelta="0" /> <alpha android:duration="1000" android:fromAlpha="0.0" android:toAlpha="1.0" /> </set>
push_bottom_out.xml
<?xml version="1.0" encoding="utf-8"?> <!-- 上下滑入式 --> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="1000" android:fromYDelta="0" android:toYDelta="50%p" /> <alpha android:duration="1000" android:fromAlpha="1.0" android:toAlpha="0.0" /> </set>
需要注意的是这两个文件是建在anim目录下的,否则不起作用。
下来主要看MainActivity中的代码,
代码我注释写的比较详细,就直接看吧
package com.feilong.popupwindow; import java.io.ByteArrayOutputStream; import java.io.File; import java.lang.reflect.Field; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.drawable.ColorDrawable; import android.view.LayoutInflater; import android.view.Menu; import android.view.View; import android.view.WindowManager; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageView; import android.widget.PopupWindow; import android.widget.PopupWindow.OnDismissListener; public class MainActivity extends Activity { private Button button; private ImageView mIvHead;//更换的图片 private View mGoneView;// 参照物 private PopupWindow mPopupWindow; // popwindow private View mpopview; // 弹出框的布局 private Bitmap photo; // 保存头像的Bitmap对象 private static final int RESULT_PICK_PHOTO_CAMERA = 1; // 退出 private static int CAMERA_RESULT = 100; // 拍照 标识码 private static int LOAD_IMAGE_RESULT = 200; // 相册 标识码 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.button1); mGoneView = findViewById(R.id.gone_view); mIvHead = (ImageView) findViewById(R.id.image_head); photo = FileUtill.readerByteArrayToSD(); // 读取保存的图片 if (photo != null) { mIvHead.setImageBitmap(photo); } else { mIvHead.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher)); } button.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { // TODO Auto-generated method stub showPopupWindon(); } }); } /** * 弹出PopupWindow */ private void showPopupWindon() { int width = getResources().getDisplayMetrics().widthPixels; int height = getResources().getDisplayMetrics().heightPixels;// px LayoutInflater inflater = LayoutInflater.from(this); mpopview = inflater.inflate(R.layout.activity_choose_picture, null);// 加载动画布局 mPopupWindow = new PopupWindow(mpopview, width, height - dip2px(50) + getStatusBarHeight());// 设置布局在屏幕中显示的位置,并且获取焦点 // 设置PopupWindow的显示样式 mPopupWindow.setAnimationStyle(R.style.PopupAnimation); // 实例化一个ColorDrawable颜色为半透明 ColorDrawable dw = new ColorDrawable(0x00000000); // 设置SelectPicPopupWindow弹出窗体的背景 mPopupWindow.setBackgroundDrawable(dw); backgroundAlpha(this, 0.5f);// 设置半透明0.0-1.0 mPopupWindow.setFocusable(true); mPopupWindow.setOutsideTouchable(false);// 设置不允许在外点击消失 // 设置当mPopupWindow取消时,界面恢复原来的颜色 不是可透明的 mPopupWindow.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss() { // TODO Auto-generated method stub backgroundAlpha(MainActivity.this, 1f);// 不透明 } }); mPopupWindow.showAsDropDown(mGoneView);// 弹出的mPopupWindow左上角正对mGoneView的左下角 // 偏移量默认为0,0 Button mTakePhotoBt = (Button) mpopview .findViewById(R.id.button_take_photo);// 拍照 Button mChoicePhotoBt = (Button) mpopview .findViewById(R.id.button_choice_photo);// 相册选择 Button mChoiceCancelBt = (Button) mpopview .findViewById(R.id.button_choice_cancel);// 取消 // 拍照 mTakePhotoBt.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mPopupWindow.dismiss(); // destoryImage(); File saveDirFile = new File(Environment .getExternalStorageDirectory(), "" + "temp.jpg"); Intent intentCamera = new Intent( MediaStore.ACTION_IMAGE_CAPTURE);// 调用系统相机拍照 intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(saveDirFile)); startActivityForResult(intentCamera, CAMERA_RESULT); } }); // 从相册选择 mChoicePhotoBt.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { mPopupWindow.dismiss();// 取消弹窗 // content://media/external/images/media 图片地址 // Intent.ACTION_PICK 从图片中选择一张 并返回选择的图片 Intent intentPhotoAlbum = new Intent( Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(intentPhotoAlbum, LOAD_IMAGE_RESULT);// 请求码200 // 打开相册 } }); // 取消 mChoiceCancelBt.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mPopupWindow.dismiss(); } }); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // 拍照 if (requestCode == CAMERA_RESULT && resultCode == RESULT_OK) { File temp = new File(Environment.getExternalStorageDirectory() + "/" + "" + "temp.jpg"); startPhotoZoom(Uri.fromFile(temp)); } // 相册选择 if (requestCode == LOAD_IMAGE_RESULT && data != null && data.getData() != null) { // Uri selectedImage = data.getData(); startPhotoZoom(data.getData()); } // 取消 if (requestCode == RESULT_PICK_PHOTO_CAMERA && data != null && data.getExtras() != null) { Bundle extras = data.getExtras(); Bitmap photo = extras.getParcelable("data"); mIvHead.setImageBitmap(photo); ByteArrayOutputStream stream = new ByteArrayOutputStream(); photo.compress(Bitmap.CompressFormat.JPEG, 60, stream); byte[] bytes = stream.toByteArray(); mIvHead.setTag(bytes); String filePath = Environment.getExternalStorageDirectory() + "/" + "" + "temp.jpg"; FileUtill.writeByteArrayToSD(filePath, bytes, true); } } /** * 设置添加屏幕的背景透明度 * * @param context * @param bgAlpha * (透明度 取值返回0-1, 0全透明,1不透明) * @date 2016年8月6日 */ public void backgroundAlpha(Activity context, float bgAlpha) { WindowManager.LayoutParams lp = context.getWindow().getAttributes(); lp.alpha = bgAlpha; context.getWindow() .addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); context.getWindow().setAttributes(lp); } /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ private int dip2px(float dpValue) { final float scale = getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * 裁剪图片方法实现 */ @SuppressLint("NewApi") public void startPhotoZoom(Uri uri) { Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, "image/*"); // 下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪 intent.putExtra("crop", "true"); // aspectX aspectY 是宽高的比例 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); // outputX outputY 是裁剪图片宽高 intent.putExtra("outputX", 200); intent.putExtra("outputY", 200); intent.putExtra("scale", true);// 黑边 intent.putExtra("scaleUpIfNeeded", true);// 黑边 intent.putExtra("return-data", true); startActivityForResult(intent, RESULT_PICK_PHOTO_CAMERA); } /** * 获取状态栏高速的方法 * * @return * @date 2016年8月7日 */ private int getStatusBarHeight() { Class<?> c = null; Object obj = null; Field field = null; int x = 0, sbar = 0; try { c = Class.forName("com.android.internal.R$dimen"); obj = c.newInstance(); field = c.getField("status_bar_height"); x = Integer.parseInt(field.get(obj).toString()); sbar = getResources().getDimensionPixelSize(x); } catch (Exception e1) { e1.printStackTrace(); } return sbar; } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
这里有几点需要注意下,1,showAsDropDown(mGoneView);这个方法,是控制popupwindow显示位置的,参数我们可以理解为一个相对参照物,它是指// 弹出的PopupWindow左上角正对mGoneView的左下角显示。难怪之前没有设置的时候怎么调宽高都不是全屏显示的。这里的mGoneView是在activity_main.xml的最上面画一条线长宽为0,状态是gone。
2,mPopupWindow = new PopupWindow(mpopview, width, height - dip2px(50)
+ getStatusBarHeight());// 设置布局在屏幕中显示的位置,并且获取焦点
这行代码主要看第三个参数。其实测试发现Android系统有的PopupWindow计算高度的时候没有计算状态栏的高度,导致不能全屏。getStatusBarHeight()方法是获取状态栏高度的,至于这个为什么要减去dip2px(50)也不是很懂,他是一个把dp转化为px的一个方法。如果不减去则有的手机下面的“取消”会看不见。
photo = FileUtill.readerByteArrayToSD(); // 读取保存的图片 if (photo != null) { mIvHead.setImageBitmap(photo); } else { mIvHead.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher)); }
之前将照片保存在手机中,以后每当打开程序它会从sd卡中读取之前保存的头像照片,并且设置显示,如果没有的话,则默认显示ic_launcher。
今天时间有点晚了,就不在细说了,稍后我会附上
源码
,大家有兴趣可以下载相关文章推荐
- H5调用手机的摄像头拍照上传以及手机相册选取照片但不支持Android的分析
- 仿QQ好友动态添加说说、图片菜单滑动移进移出效果--在指定控件下面显示popupwindow动画不移效果
- 自定义PopupWindow,带显示隐藏动画、全屏背景以及触摸屏幕空白区域消失的功能
- 更换用户头像 调用手机相册或相机拍照 选择图片并裁剪
- Android设置头像,手机拍照或从本地相册选取图片作为头像
- Android设置头像,手机拍照或从本地相册选取图片作为头像
- Android拍照存储文件报open failed: ENOENT (No such file or directory)(适配不同手机的方法)以及6.0动态权限
- Android设置头像,手机拍照或从本地相册选取图片作为头像
- Android通过手机拍照或从本地相册选取图片设置头像
- 【Android笔记】Androd手机拍照或从相册选取图片作为头像
- Android实现从手机相册上传头像以及拍照上传到服务器
- Android设置头像,手机拍照或从本地相册选取图片作为头像
- H5调用手机的摄像头拍照上传以及手机相册选取照片
- Android设置头像,手机拍照或从本地相册选取图片作为头像
- PopupWindow弹出框与背景变暗的实现(附带动画效果)
- PopupWindow显示和消失动画,以及界面切换时动画所导致的问题
- android学习笔记---49_屏幕适配,根据不同手机屏幕大小适配软件界面
- [Android实例] ViewPager多页面滑动切换以及动画效果【转】
- android学习笔记---49_屏幕适配,根据不同手机屏幕大小适配软件界面
- Android平板上开发应用的一点心得——精确适配不同的dpi和屏幕尺寸