700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > android调取手机相册或打开相机选择图片并显示

android调取手机相册或打开相机选择图片并显示

时间:2023-11-05 12:47:21

相关推荐

android调取手机相册或打开相机选择图片并显示

作为一个android小白,自己想尝试写一个小项目,因此写个小博客记录一下自己的开发历程。这一篇记录自己学习调取手机相册以及打开相机选择图片并显示

示例是采用PopupWindow弹出底部菜单,选择相应按钮,来显示图片。

第一步:加载好PopupWindow控件,具体代码如下(不详情描述):

PopupWindow控件的xml文件

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="/apk/res/android"android:layout_width="fill_parent"android:layout_height="wrap_content"android:gravity="center_horizontal"android:orientation="vertical" ><LinearLayoutandroid:id="@+id/pop_layout"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:gravity="center_horizontal"android:orientation="vertical" ><Buttonandroid:id="@+id/takePhotoBtn"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="10dip"android:layout_marginRight="10dip"android:layout_marginTop="10dp"android:background="#373447"android:padding="10dp"android:text="拍照"android:textColor="#CEC9E7"android:textSize="18sp"android:textStyle="bold" /><Buttonandroid:id="@+id/pickPhotoBtn"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="10dip"android:layout_marginRight="10dip"android:layout_marginTop="5dp"android:background="#373447"android:padding="10dp"android:text="从相册选择"android:textColor="#CEC9E7"android:textSize="18sp"android:textStyle="bold" /><Buttonandroid:id="@+id/cancelBtn"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="15dip"android:layout_marginLeft="10dip"android:layout_marginRight="10dip"android:layout_marginTop="20dp"android:background="@android:color/white"android:padding="10dp"android:text="取消"android:textColor="#373447"android:textSize="18sp"android:textStyle="bold" /></LinearLayout></RelativeLayout>

对应的继承PopupWindow的java代码:

public class ChoosePicPopWindow extends PopupWindow {private Button takePhotoBtn, pickPhotoBtn, cancelBtn;private View mMenuView;@SuppressLint("InflateParams")public ChoosePicPopWindow(Context context, View.OnClickListener itemsOnClick) {super(context);LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);mMenuView = inflater.inflate(R.layout.item_choosepicture, null);takePhotoBtn = (Button) mMenuView.findViewById(R.id.takePhotoBtn);pickPhotoBtn = (Button) mMenuView.findViewById(R.id.pickPhotoBtn);cancelBtn = (Button) mMenuView.findViewById(R.id.cancelBtn);cancelBtn.setOnClickListener(itemsOnClick);pickPhotoBtn.setOnClickListener(itemsOnClick);takePhotoBtn.setOnClickListener(itemsOnClick);//为choosePicPopWindow设置底部菜单视图this.setContentView(mMenuView);//设置宽度this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);//设置高度this.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);//是否可点击this.setFocusable(true);//设置弹出窗体动画效果this.setAnimationStyle(R.style.PopupAnimation);//实例化一个颜色为半透明ColorDrawable dw = new ColorDrawable(0x80000000);//设置弹出窗口为半透明this.setBackgroundDrawable(dw);//mMenuView添加OnTouchListener监听判断获取触屏位置如果在选择框外面则销毁弹出框mMenuView.setOnTouchListener(new View.OnTouchListener() {@Override@SuppressLint("ClickableViewAccessibility")public boolean onTouch(View v, MotionEvent event) {int height = mMenuView.findViewById(R.id.pop_layout).getTop();int y = (int) event.getY();if (event.getAction() == MotionEvent.ACTION_UP) {if (y < height) {dismiss();}}return true;}});}}

其中涉及的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>

弹出窗口的动画效果文件

(1)push_button_in.xml

<?xml version="1.0" encoding="utf-8"?><!-- 上下滑入式 --><set xmlns:android="/apk/res/android" ><translateandroid:duration="200"android:fromYDelta="100%p"android:toYDelta="0" /> <alphaandroid:fromAlpha="0.0"android:toAlpha="1.0"android:duration="200"/></set>

(2)push_button_out.xml

<?xml version="1.0" encoding="utf-8"?><!-- 上下滑入式 --><set xmlns:android="/apk/res/android" ><translateandroid:duration="200"android:fromYDelta="0"android:toYDelta="50%p" /><alphaandroid:fromAlpha="1.0"android:toAlpha="0.0"android:duration="200"/></set>

第二步:填入申请的权限

<!--相机的权限--><uses-permission android:name="android.permission.CAMERA"/><!--获取sd卡写的权限,用于文件上传和下载--><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

第三步:点击“相册”按钮,进入相册选取图片然后显示

1.点击按钮判断权限,并发出读取相册意图

if(v.getId() == R.id.pickPhotoBtn){Toast.makeText(MainActivity.this,"选择本地照片",Toast.LENGTH_SHORT).show();//进行权限的判断,看是否申请权限if (ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) {// 权限还没有授予,进行申请ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 200); // 申请的 requestCode 为 200} else {// 如果权限已经申请过,直接进行图片选择mpopWindow.dismiss();//关闭底部窗口//传递读取本地相册意图Intent intent = new Intent(Intent.ACTION_PICK);intent.setType("image/*");// 判断系统中是否有处理该 Intent 的 Activityif (intent.resolveActivity(getPackageManager()) != null) {startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE);} else {Toast.makeText(MainActivity.this, "未找到图片查看器", Toast.LENGTH_SHORT).show();}}}

注:上面代码的常量以及变量

private static final int REQUEST_CODE_PICK_IMAGE = 0; //选择图片private static final int REQUEST_CODE_CAPTURE_CAMEIA = 1; //拍照private static final String IMAGE_FILE_NAME = "user_head_icon.jpg";//拍照之后的图片名称private Uri userImageUri;//保存用户头像的ur

2.接受回调的信息(即获取选择好图片返回的uri):

@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {Uri imageUri;//resultCode参数为返回的信息,为 RESULT_CANCELED表示失败(简单理解)if (resultCode == RESULT_CANCELED) {Toast.makeText(MainActivity.this, "获取失败", Toast.LENGTH_SHORT).show();img.setImageDrawable(getResources().getDrawable(R.drawable.img_1));//预设的图片} else if(resultCode == RESULT_OK){//成功switch (requestCode) {//相册照片选择case REQUEST_CODE_PICK_IMAGE:{//对应上面的常量//返回选择图片的uri,参数data.getData()方法获得imageUri = data.getData();//通过uri的方式返回,部分手机uri可能为空Bitmap bm = null;if(imageUri != null){try {//将获得的图片uri进行压缩,不然图片像素过大,可能会出现错误bm = getBitmapFormUri(imageUri);//此方法在下面} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}else {//部分手机可能直接存放在bundle中Bundle bundleExtras = data.getExtras();if(bundleExtras != null){bm = bundleExtras.getParcelable("data");}}img.setImageBitmap(bm);//显示图片break;}

注:在相册选择的图片,会下面拍照之后的照片都可能需要压缩像素,不然像素过大,可能会出现问题。下面这段代码可以不需要理解,太麻烦直接粘贴复制就好

//压缩图片像素public Bitmap getBitmapFormUri(Uri uri) throws FileNotFoundException, IOException {InputStream input = getContentResolver().openInputStream(uri);//这一段代码是不加载文件到内存中也得到bitmap的真是宽高,主要是设置inJustDecodeBounds为trueBitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();onlyBoundsOptions.inJustDecodeBounds = true;//不加载到内存onlyBoundsOptions.inDither = true;//optionalonlyBoundsOptions.inPreferredConfig = Bitmap.Config.RGB_565;//optionalBitmapFactory.decodeStream(input, null, onlyBoundsOptions);input.close();int originalWidth = onlyBoundsOptions.outWidth;int originalHeight = onlyBoundsOptions.outHeight;if ((originalWidth == -1) || (originalHeight == -1))return null;//图片分辨率以480x800为标准float hh = 800f;//这里设置高度为800ffloat ww = 480f;//这里设置宽度为480f//缩放比,由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可int be = 1;//be=1表示不缩放if (originalWidth > originalHeight && originalWidth > ww) {//如果宽度大的话根据宽度固定大小缩放be = (int) (originalWidth / ww);} else if (originalWidth < originalHeight && originalHeight > hh) {//如果高度高的话根据宽度固定大小缩放be = (int) (originalHeight / hh);}if (be <= 0)be = 1;//比例压缩BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();bitmapOptions.inSampleSize = be;//设置缩放比例bitmapOptions.inDither = true;bitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;input = getContentResolver().openInputStream(uri);Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);input.close();return compressImage(bitmap);//再进行质量压缩}public Bitmap compressImage(Bitmap image) {ByteArrayOutputStream baos = new ByteArrayOutputStream();press(pressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中int options = 100;while (baos.toByteArray().length / 1024 > 100) { //循环判断如果压缩后图片是否大于100kb,大于继续压缩baos.reset();//重置baos即清空baos//第一个参数 :图片格式 ,第二个参数: 图片质量,100为最高,0为最差 ,第三个参数:保存压缩后的数据的流press(pressFormat.JPEG, options, baos);//这里压缩options,把压缩后的数据存放到baos中options -= 10;//每次都减少10if (options<=0)break;}ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片return bitmap;}

第三步:调取相机拍照,并显示图片

1.点击按钮,判断权限,并打开相机拍照

else if(v.getId() == R.id.takePhotoBtn){Toast.makeText(MainActivity.this,"照相",Toast.LENGTH_SHORT).show();if (ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED|| ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) {// 权限还没有授予,进行申请ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 300); // 申请的 requestCode 为 300} else {// 权限已经申请,直接拍照mpopWindow.dismiss();imageCapture();}}

2.拍完照,发送意图

//跳转到拍照,拍完并intent发送请求private void imageCapture() {Intent intent;//也就是我存放头像的文件夹(目录)File pictureFile = new File(Environment.getExternalStorageDirectory()+File.separator+"MyText", IMAGE_FILE_NAME);//第二个参数为图片的名字,在上面常量里if(!pictureFile.getParentFile().exists()){pictureFile.getParentFile().mkdirs();}// 判断当前系统,android7.0以上版本if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);/*FileProvider是ContentProvider的一个子类,用于应用程序之间私有文件的传递,需要在清单里配置,代码在下方。实际的getUriForFile就是FileProvider.getUriForFile("上下文","清单文件中authorities的值","共享的文件");*/userImageUri = FileProvider.getUriForFile(MainActivity.this,"com.example.dell.test", pictureFile);} else {intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);userImageUri = Uri.fromFile(pictureFile);}// 去拍照,拍照的结果存到oictureUri对应的路径中intent.putExtra(MediaStore.EXTRA_OUTPUT, userImageUri);Log.e(TAG,"before take photo"+userImageUri.toString());startActivityForResult(intent, REQUEST_CODE_CAPTURE_CAMEIA);}

注:(1)清单的配置

<application***<provider<!--name为FileProvider所在的v4报的路径,不需要改就这么填-->android:name="android.support.v4.content.FileProvider"<!--这个为自己定义,在上面getUriForFile的第二个参数就是这个,建议为自己demo的包名-->android:authorities="com.example.dell.test"<!--代表是否可以输出被外部程序使用,填false就行-->android:exported="false"<!-- 是否允许为文件授予临时权限,必须为true-->android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"<!--对应的xml文件路径-->android:resource="@xml/provider_paths" /></provider>

(2)指定可共享的文件路径

(这一部分不好理解,可以去参考这个大神,/p/6c51202c845d)

<?xml version="1.0" encoding="utf-8"?><paths xmlns:android="/apk/res/android"><external-path path="MyText/" name="MyTextRoot" /><external-path name="sdcard_root" path="."/></paths>

3.得到uri,然后显示即可全部完成

case REQUEST_CODE_CAPTURE_CAMEIA: {//拍照常量Bitmap bm1 = null;try {bm1 = getBitmapFormUri(userImageUri);//压缩照片} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}img.setImageBitmap(bm1);//显示照片break;}

以上即可完成。最终效果是在真机上显示,所以无法放在这上面

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。