安卓不同機(jī)型和API版本中拍照和相冊(cè)選取照片功能實(shí)現(xiàn)

該demo針對(duì)不同機(jī)型和不同API進(jìn)行功能實(shí)現(xiàn),滿足大部分手機(jī)拍照和相冊(cè)選取照片功能實(shí)現(xiàn)。
1使用知乎相冊(cè)框架compile 'com.zhihu.android:matisse:0.4.3'進(jìn)行圖庫(kù)相冊(cè)選取
2使用compile 'com.github.bumptech.glide:glide:3.7.0'框架(Glide)進(jìn)行圖片加載


如下效果

1點(diǎn)擊選擇圖片按鈕彈出popuwindow


01.png

2拍照:


02.png

3相冊(cè)選取:


03.png

4選擇的結(jié)果:
04.png

SelectPicPopup的代碼:

package study.lzl.photoselectdemo;

import android.content.Context;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.PopupWindow;

/**
 * @author: Created by lzl on 2017/8/14.
 * @function:
 * @description:
 */

public class SelectPicPopup implements View.OnClickListener {
    /**
     * UI
     */
    private PopupWindow mPopupWindow;
    private Button mCameraBtn;//相冊(cè)
    private Button mPicBtn;//圖庫(kù)
    private Button mCancelBtn;//取消
    private Context mContext;//上下文環(huán)境對(duì)象

    private OnBtnClickListener click;

    public PopupWindow getmPopupWindow() {
        return mPopupWindow;
    }

    /**
     * 單參構(gòu)造
     * @param mContext
     */
    public SelectPicPopup(Context mContext) {
        this.mContext = mContext;
        mPopupWindow=new PopupWindow(mContext);
        mPopupWindow.setBackgroundDrawable(new BitmapDrawable());
        mPopupWindow.setWidth(WindowManager.LayoutParams.MATCH_PARENT);//寬度充滿父窗體
        mPopupWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);//高度包裹內(nèi)容
        mPopupWindow.setTouchable(true);//設(shè)置可以被觸摸
        mPopupWindow.setFocusable(true);//設(shè)置占據(jù)焦點(diǎn)
        mPopupWindow.setOutsideTouchable(true);//設(shè)置可以點(diǎn)擊外部區(qū)域(點(diǎn)擊外部區(qū)域?qū)⑾?
        mPopupWindow.setContentView(initView());
        mPopupWindow.setAnimationStyle(R.style.AnimBottom);//設(shè)置轉(zhuǎn)場(chǎng)動(dòng)畫
        mPopupWindow.getContentView().setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                mPopupWindow.setFocusable(false);
                dismiss();
                return false;
            }
        });
    }

    private View initView() {
        View view= LayoutInflater.from(mContext).inflate(R.layout.layout_popup,null);
        mCameraBtn= (Button) view.findViewById(R.id.camera_btn);
        mCameraBtn.setOnClickListener(this);

        mPicBtn= (Button) view.findViewById(R.id.pic_btn);
        mPicBtn.setOnClickListener(this);
        mCancelBtn= (Button) view.findViewById(R.id.cancel_btn);
        mCancelBtn.setOnClickListener(this);
        return view;
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.camera_btn:
                click.getFlag(0);
                break;
            case R.id.pic_btn:
                click.getFlag(1);
                break;
            case R.id.cancel_btn:
                dismiss();
                break;
        }
    }

    protected void dismiss(){
        if (mPopupWindow!=null&&mPopupWindow.isShowing()){
            mPopupWindow.dismiss();
        }
    }

    /**
     *
     * @param rootView
     */
    protected void showPopup(View rootView){
        mPopupWindow.showAtLocation(rootView, Gravity.BOTTOM,0,0);
    }

    protected interface OnBtnClickListener{
        void getFlag(int flag);
    }

    protected void setOnBtnClick(OnBtnClickListener click){
        this.click=click;
    }
}

自定義的popuwindow使用的style如下:

<!--popuwindow style-->
    <style name="AnimBottom" parent="@android:style/Animation">
        <item name="android:windowEnterAnimation">@anim/popup_alpha_out</item>
        <item name="android:windowExitAnimation">@anim/popup_alpha_in</item>
    </style>

引用的兩個(gè)anim文件:
1anim/popup_alpha_out:

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:fromAlpha="0.0"
    android:toAlpha="1.0"
    >

</alpha>

2anim/popup_alpha_in:

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:fromAlpha="1.0"
    android:toAlpha="0.0"
    >

</alpha>

布局文件:layout_popup.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/half_transparent_black">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_alignParentBottom="true"
        android:background="@color/page_bg_color">
        <Button
            android:id="@+id/camera_btn"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="#ffffff"
            android:text="拍照"
            android:textColor="#000"
            />
        <View
            android:layout_width="match_parent"
            android:layout_height="0.5dp"
            android:background="#65000000"/>
        <Button
            android:id="@+id/pic_btn"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:text="相冊(cè)"
            android:textColor="#000"
            android:background="#ffffff"/>
        <Button
            android:id="@+id/cancel_btn"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_marginTop="10dp"
            android:background="#ffffffff"
            android:textColor="#000"
            android:text="取消"/>
    </LinearLayout>
</RelativeLayout>

MainActivity的代碼:

package study.lzl.photoselectdemo;

import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;

import com.zhihu.matisse.Matisse;
import com.zhihu.matisse.MimeType;
import com.zhihu.matisse.engine.impl.GlideEngine;

import java.io.File;
import java.util.List;

/**
 * 演示圖片選擇來(lái)源,并將圖片正確顯示在控件上,該控件可以對(duì)圖片進(jìn)行手勢(shì)操作:包括大小縮放和平移拖拽
 */
public class MainActivity extends AppCompatActivity {
    private ImageView imageV;
    private Uri imageUrl;//照片地址uri對(duì)象
    private int destType = FileHelper.JPEG;
    private static final int REQUEST_CODE_TAKE_PIC_CAMERA = 100;//拍照請(qǐng)求碼

    private static final int REQUEST_CODE_CHOOSE = 233;//圖庫(kù)選取照片請(qǐng)求碼

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        imageV= (ImageView) findViewById(R.id.image);
        findViewById(R.id.select_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                final SelectPicPopup popup=new SelectPicPopup(getApplicationContext());
                popup.showPopup(findViewById(R.id.activity_main));
                popup.setOnBtnClick(new SelectPicPopup.OnBtnClickListener() {
                    @Override
                    public void getFlag(int flag) {
                        if (flag==1){//相冊(cè)
                            popup.dismiss();
                            selectPicFromGallery();
                        }else if (flag==0){//拍照
                            popup.dismiss();
                            if (hasPermission(PerMissionContants.HARDWEAR_CAMERA_PERMISSION)){
                                openCamera();
                            }else {
                                requestPermission(PerMissionContants.HARDWEAR_CAMERA_CODE,PerMissionContants.HARDWEAR_CAMERA_PERMISSION);
                                Toast.makeText(getApplicationContext(),"權(quán)限:"+hasPermission(PerMissionContants.HARDWEAR_CAMERA_PERMISSION),Toast.LENGTH_SHORT).show();
                            }
                        }
                    }
                });
            }
        });
    }

    /**
     * 打開相冊(cè)進(jìn)行拍照
     */
    private void openCamera() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //創(chuàng)建一個(gè)臨時(shí)文件夾存儲(chǔ)拍攝的照片
        File file = FileHelper.createFileByType(getApplicationContext(), destType, System.currentTimeMillis()+"");
        imageUrl=Uri.fromFile(file);//解析出uri對(duì)象
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//版本過(guò)高的拍照路徑
            Log.e("進(jìn)入1","進(jìn)入1");
            file = new File(getApplicationContext().getCacheDir(), System.currentTimeMillis()+".jpg");
            imageUrl = Uri.fromFile(file);

            Toast.makeText(getApplicationContext(), "TODO", Toast.LENGTH_SHORT).show();
            // 將文件轉(zhuǎn)換成content://Uri的形式
            Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), getPackageName() + ".provider", file);
            // 申請(qǐng)臨時(shí)訪問(wèn)權(quán)限
            takePictureIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);

        } else {
            Log.e("進(jìn)入2","進(jìn)入2");
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUrl);
        }


        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
            Log.e("進(jìn)入3","進(jìn)入3");
            startActivityForResult(takePictureIntent, REQUEST_CODE_TAKE_PIC_CAMERA);
        }
    }

    /**
     * 打開相冊(cè)選取照片
     */
    private void selectPicFromGallery() {
        Matisse.from(MainActivity.this)
                .choose(MimeType.allOf())
                .countable(true)
                .spanCount(4)
                .maxSelectable(1)
                .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
                .thumbnailScale(0.85f)
                .imageEngine(new GlideEngine())
                .forResult(REQUEST_CODE_CHOOSE);
    }

    /**
     * 發(fā)起權(quán)限請(qǐng)求
     */
    private void requestPermission(int code,String...permissions){
        if (Build.VERSION.SDK_INT>=23){//判斷是否大于6.0版本(當(dāng)前手機(jī)的安卓系統(tǒng)是否是6.0或以上)
            requestPermissions(permissions,code);
        }
    }

    /**
     * 校驗(yàn)權(quán)限是否通過(guò)(安卓6.0以上的動(dòng)態(tài)權(quán)限需要調(diào)用該方法)
     * @param permissions
     * @return
     */
    private boolean hasPermission(String...permissions){
        for (String permission:permissions) {
            if (ContextCompat.checkSelfPermission(getApplicationContext(),permission)!= PackageManager.PERMISSION_GRANTED){
                return false;
            }
        }
        return true;
    }

    /**
     * 權(quán)限請(qǐng)求回調(diào)結(jié)果處理
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode==PerMissionContants.HARDWEAR_CAMERA_CODE){//拍照權(quán)限
            if (grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
                Toast.makeText(getApplicationContext(),"權(quán)限請(qǐng)求結(jié)果",Toast.LENGTH_SHORT).show();
                openCamera();
            }

        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode==REQUEST_CODE_TAKE_PIC_CAMERA&&resultCode==RESULT_OK){//拍照請(qǐng)求回調(diào)成功
            if (imageUrl!=null){
                //根據(jù)uri獲取圖片的真實(shí)路徑
                String path=getRealFilePath(getApplicationContext(),imageUrl);
                Bitmap bitmap=BitmapFactory.decodeFile(path);//根據(jù)圖片的路徑字符串解析成bitmap
                imageV.setImageBitmap(bitmap);
            }
        }else if (requestCode==REQUEST_CODE_CHOOSE&&resultCode==RESULT_OK){
            List<Uri> uriList=Matisse.obtainResult(data);
            if (uriList.size()==1){
                String path=getRealFilePath(getApplicationContext(),uriList.get(0));
                Bitmap bitmap=BitmapFactory.decodeFile(path);//根據(jù)圖片的路徑字符串解析成bitmap
                imageV.setImageBitmap(bitmap);
            }
        }
    }

    /**
     * 該方法根據(jù)圖片uri得出其真實(shí)路徑
     * @param context 上下文
     * @param uri 圖片對(duì)應(yīng)的uri對(duì)象
     * @return 圖片的真實(shí)路徑字符串
     */
    public String getRealFilePath(final Context context, final Uri uri) {
        if (null == uri) return null;
        final String scheme = uri.getScheme();
        String data = null;
        if (scheme == null)
            data = uri.getPath();
        else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
            data = uri.getPath();
        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
            Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.Images.ImageColumns.DATA}, null, null, null);
            if (null != cursor) {
                if (cursor.moveToFirst()) {
                    int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
                    if (index > -1) {
                        data = cursor.getString(index);
                    }
                }
                cursor.close();
            }
        }
        return data;
    }
}

布局文件:activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="study.lzl.photoselectdemo.MainActivity">

    <Button
        android:id="@+id/select_btn"
        android:background="@color/colorAccent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="選擇照片"
        android:textColor="@color/colorPrimary"/>

    <ImageView
        android:id="@+id/image"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerInParent="true"/>

</RelativeLayout>


動(dòng)態(tài)權(quán)限常量類:PerMissionContants

package study.lzl.photoselectdemo;

import android.Manifest;

/**
 * @author: Created by lzl on 2017/8/15.
 * @function:
 * @description:
 */

public class PerMissionContants {
    /**
     * 拍照權(quán)限碼
     */
    public static final int HARDWEAR_CAMERA_CODE=0x01;
    /**
     * 拍照用到的權(quán)限字符串?dāng)?shù)組:1打開數(shù)組的權(quán)限  2文件的寫入權(quán)限(拍照要緩存) 3所拍照片的獲?。◤谋镜鼐彺婊蛘呦鄡?cè)中獲取)
     */
    public static final String[] HARDWEAR_CAMERA_PERMISSION=new String[]{Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE};
}


文件操作助手類:FileHelper

package study.lzl.photoselectdemo;

import android.content.Context;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by rookie on 2017/2/28.
 */

public class FileHelper {
    public static final int JPEG = 1;
    static final int PNG = 0;


    /**
     * 返回系統(tǒng)緩存路徑
     *
     * @param mContext
     * @return
     */
    public static String getTempDirectoryPath(Context mContext) {
        File cachePath;
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            cachePath = mContext.getExternalCacheDir();
        } else {
            cachePath = mContext.getCacheDir();
        }
        cachePath.mkdirs();
        return cachePath.getAbsolutePath();
    }

    /**
     * 在系統(tǒng)緩存中創(chuàng)建一個(gè)文件
     *
     * @param mContext
     * @param type
     * @param name
     * @return
     */
    public static File createFileByType(Context mContext, int type, String name) {
        if (TextUtils.isEmpty(name)) {
            name = ".pic";
        }

        switch (type) {
            case JPEG:
                name = name + ".jpg";
                break;
            case PNG:
                name = name + ".png";
                break;
            default:
                break;

        }
        return new File(getTempDirectoryPath(mContext), name);

    }

    /**
     * Removes the "file://" prefix from the given URI string, if applicable.
     * If the given URI string doesn't have a "file://" prefix, it is returned unchanged.
     *
     * @param uriString the URI string to operate on
     * @return a path without the "file://" prefix
     */
    public static String stripFileProtocol(String uriString) {
        if (uriString.startsWith("file://")) {
            uriString = uriString.substring(7);
        }
        return uriString;
    }

    public static String getPicutresPath(int encodingType) {
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "IMG_" + timeStamp + (encodingType == JPEG ? ".jpg" : ".png");
        File storageDir = Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_DCIM);
        String galleryPath = storageDir.getAbsolutePath() + File.separator + "Camera" + File.separator + imageFileName;
        return galleryPath;
    }

    public static boolean copyResultToGalley(Context context, Uri originUri, Uri galleryUri) {
        boolean result = false;
        InputStream inputStream = null;
        OutputStream outputStream = null;

        try {
            inputStream = context.getContentResolver().openInputStream(originUri);
            outputStream = context.getContentResolver().openOutputStream(galleryUri);

            byte[] buffer = new byte[2048];

            int len;
            while ((len = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
            }
            outputStream.flush();
            result = true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }
}

***

注意事項(xiàng):
1在app.gradle配置文件中配置使用到的兩個(gè)框架:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    testCompile 'junit:junit:4.12'
    //項(xiàng)目中需要用到的第三方框架
    compile 'com.zhihu.android:matisse:0.4.3'
    compile 'com.github.bumptech.glide:glide:3.7.0'
}

2安卓6.0以上版本使用的是動(dòng)態(tài)權(quán)限管理:因此增加一個(gè)類進(jìn)行權(quán)限的申請(qǐng)?zhí)幚?PerMissionContants

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,922評(píng)論 25 709
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,536評(píng)論 19 139
  • 一.榜單介紹 排行榜包括四大類: 單一框架:僅提供路由、網(wǎng)絡(luò)層、UI層、通信層或其他單一功能的框架 混合開發(fā)框架:...
    偉子男閱讀 5,356評(píng)論 0 161
  • 金融理財(cái)產(chǎn)品的銷售渠道合集: 首先,給我們的客戶定位,以ABCD類來(lái)定位客戶: A類:有錢有意向 B類:有錢無(wú)意向...
    畫與話閱讀 1,336評(píng)論 1 0
  • 一個(gè)電商產(chǎn)品設(shè)計(jì)中圖片占據(jù)80%,所以圖片的質(zhì)量對(duì)整體設(shè)計(jì)品質(zhì)有直接影響。 上圖中左邊的界面比右邊的界面更舒適、更...
    fcfdesign閱讀 428評(píng)論 0 0

友情鏈接更多精彩內(nèi)容