您的位置:首页 > 运维架构

PopupWindow全屏显示以及适配不同手机屏幕之 应用实例 更换头像,拍照,相册选取附带动画效果

2017-03-06 23:57 841 查看
最近找工作,所以闲余时间还是比较充足的,今晚刚好没有睡意,抽取了一个之前项目中自己写过的一个功能。更换头像,可以拍照,可以从相册选取照片,有裁剪功能。其中的一个坑是PopupWindow的显示位置以及是否全屏显示适配不同手机。

话不多少,先上效果。





因为这个效果展示时间比较长,所以分了两段录结果还是大了,把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。

今天时间有点晚了,就不在细说了,稍后我会附上

源码

,大家有兴趣可以下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐