Android專案實踐——三行程式碼解決照片選擇與壓縮

Anlia發表於2017-12-23

版權宣告:本文為博主原創文章,未經博主允許不得轉載

系列教程:Android開發之從零開始系列

原始碼:AnliaLee/PhotoFactory,歡迎star

大家要是看到有錯誤的地方或者有啥好的建議,歡迎留言評論

初看標題是不是覺得博主是標題黨,故意把你們騙了進來?告訴你

Android專案實踐——三行程式碼解決照片選擇與壓縮

博主幫大家封裝好了PhotoFactory類,只需三行程式碼就可以完成選擇照片,獲取其bitmap或uri路徑(可自行配置是否壓縮)的功能。下面來看下如何使用PhotoFactory


PhotoFactory簡介

使用PhotoFactory分為三步,首先我們要例項化一個photoFactory

PhotoFactory photoFactory = new PhotoFactory(this, this);//(Activity activity,Context context)
複製程式碼

設定選擇照片的方式

//提供三種選擇照片的方式
photoFactory.FactoryStart().SetStartType(PhotoFactory.TYPE_PHOTO_UNTREATED).Start();//呼叫相機拍照,照相後返回高清原圖相片
/*photoFactory.FactoryStart().SetStartType(PhotoFactory.TYPE_PHOTO_AUTO_COMPRESS).Start();//呼叫相機拍照,照相後返回系統自動壓縮過的相片
photoFactory.FactoryStart().SetStartType(PhotoFactory.TYPE_PHOTO_FROM_GALLERY).Start();//從本地相簿中選取圖片*/
複製程式碼

獲取相片bitmap或uri

/**
 * 在onActivityResult中呼叫此方法
 */
photoFactory.FactoryFinish(requestCode,resultCode,data).GetBitmap();
//photoFactory.FactoryFinish(requestCode,resultCode,data).GetUri();
複製程式碼

就這麼簡單,當然,你還可以對照片進行壓縮處理,這裡提供了三種壓縮的方式

addScaleCompress(int w, int h)//按目標寬高縮放
addScaleCompress(int scale)//等比例縮放,縮放比為 原圖:新圖 = scale:1
addQualityCompress(int targetSize)//質量壓縮,targetSize為目標大小
複製程式碼

你可以選擇其中一種或多種壓縮方式對相片進行壓縮,例如

//只選擇一種壓縮方式
photoFactory.FactoryFinish(requestCode,resultCode,data)
	    .addQualityCompress(128)
	    .GetBitmap();
	    
//按順序逐步壓縮
photoFactory.FactoryFinish(requestCode,resultCode,data)
	    .addQualityCompress(128)
	    .addScaleCompress(5)
	    .addScaleCompress(300,300)
	    .GetBitmap();
複製程式碼

完整示例

PhotoFactory相容了Android 7.0 FileProvider獲取相片uri的問題,當然具體Provider的配置以及Android 6.0的動態許可權管理需要大家在專案中自行完成。這裡為了方便大家完成配置,我將完整的流程貼出來供大家參考

1.在Github下載photofactory library並匯入到你的專案中

地址:AnliaLee/PhotoFactory

2. 在res\xml目錄中建立provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>
複製程式碼

3. 在AndroidManifest.xml中新增相應許可權及配置Provider

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
	android:icon="@mipmap/ic_launcher"
	...
	>
	<provider
		android:name="android.support.v4.content.FileProvider"
		android:authorities="${applicationId}.provider"
		android:exported="false"
		android:grantUriPermissions="true">
		<meta-data
			android:name="android.support.FILE_PROVIDER_PATHS"
			android:resource="@xml/provider_paths" />
	</provider>
	...
</application>
複製程式碼

4. 在AndroidManifest.xml中新增相應許可權及配置Provider

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
	android:icon="@mipmap/ic_launcher"
	...
	>
	<provider
		android:name="android.support.v4.content.FileProvider"
		android:authorities="${applicationId}.provider"
		android:exported="false"
		android:grantUriPermissions="true">
		<meta-data
			android:name="android.support.FILE_PROVIDER_PATHS"
			android:resource="@xml/provider_paths" />
	</provider>
	...
</application>
複製程式碼

5. 在Activity中進行動態許可權管理以及使用PhotoFactory

public class PhotoTestActivity extends AppCompatActivity {
    private Button btnPhoto;
    private ImageView imgPhoto;
    private PhotoFactory photoFactory;

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

        photoFactory = new PhotoFactory(this,this);
        imgPhoto = (ImageView) findViewById(R.id.img_photo);
        btnPhoto = (Button) findViewById(R.id.btn_photo);
        btnPhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (ContextCompat.checkSelfPermission(PhotoTestActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    //申請寫入許可權
                    ActivityCompat.requestPermissions(PhotoTestActivity.this, new String[]{
                            Manifest.permission.WRITE_EXTERNAL_STORAGE
                    }, 100);
                } else {
                    photoFactory.FactoryStart()
                                .SetStartType(PhotoFactory.TYPE_PHOTO_UNTREATED)
                                .Start();
                }
            }
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch(requestCode) {
            case 100:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    photoFactory.FactoryStart()
                            .SetStartType(PhotoFactory.TYPE_PHOTO_UNTREATED)
                            .Start();
                }else{// 沒有獲取到許可權,做特殊處理
                    Toast.makeText(this, "請授予許可權!", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(requestCode == RESULT_CANCELED){
            Toast.makeText(this, "取消拍照!", Toast.LENGTH_SHORT).show();
        }else {
            if(data == null){
                Toast.makeText(this, "取消選擇!", Toast.LENGTH_SHORT).show();
                return;
            }
            //使用你選取的照片
            Uri uri = photoFactory.FactoryFinish(requestCode,resultCode,data).GetUri();
            imgPhoto.setImageURI(uri);
        }
        super.onActivityResult(requestCode, resultCode, data);
    }
}
複製程式碼

PhotoFactory至此介紹完畢,具體實現並不複雜,有興趣瞭解內部是如何實現的可以自行查閱原始碼,如果有不懂的地方或者檢查到程式碼有什麼問題歡迎給我留言~


更新

之前的程式碼雖然簡化了選取照片的過程,但沒有考慮到把取消選擇的處理也封裝進來,使用者還得在onActivityResult中寫一堆程式碼去處理取消選擇的情況,這說明PhotoFactory用起來還不夠方便,於是我動手增加了判斷取消選擇的介面,現在我們可以呼叫這些新的介面進行容錯了

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	//依然可以這樣去獲取相片,但需要你自己去寫取消選擇的處理
	Uri uri = photoFactory.FactoryFinish(requestCode,resultCode,data).GetUri();
	imgPhoto.setImageURI(uri);

	//現在只要這樣呼叫setOnResultListener就可以一步到位了
	photoFactory.FactoryFinish(requestCode,resultCode,data)
				.setOnResultListener(new PhotoFactory.OnResultListener() {
		@Override
		public void TakePhotoCancel() {
			Toast.makeText(PhotoTestActivity.this, "取消拍照", Toast.LENGTH_SHORT).show();
		}

		@Override
		public void GalleryPhotoCancel() {
			Toast.makeText(PhotoTestActivity.this, "取消選擇", Toast.LENGTH_SHORT).show();
		}

		@Override
		public void HasData(PhotoFactory.FinishBuilder resultData) {//正確選取了相片
			Uri uri = resultData.GetUri();
			imgPhoto.setImageURI(uri);
		}
	});
	super.onActivityResult(requestCode, resultCode, data);
}
複製程式碼

但是...這樣好像就不止三行程式碼了啊...

Android專案實踐——三行程式碼解決照片選擇與壓縮

相關文章