關於Android點擊頭像顯示窗口調用相機與相冊
主要有七步:
點擊事件,窗口初始化,點擊回調事件,對照片裁剪,裁剪照片保存,聲明FileProvider,編寫FileProvider的xml文件
1.點擊事件
這裏只簡單的設置了一個圖片,還有他的點擊事件
fun onClick(v:View){
when(v.id){
R.id.main_imagV -> show()
}
}
2.窗口的初始化
fun show() {
val dialog = Dialog(this)
val inflate = layoutInflater.inflate(R.layout.activity_second2, null)
val xiangji:Button = inflate.findViewById(R.id.xiangji)
val xiangce:Button = inflate.findViewById(R.id.xiangce)
xiangji.setOnClickListener {
dialog.dismiss() //點擊按鈕窗口消失
REQUEST_CODE = 1 //事件請求CODE爲1
outputImage = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES),"最近一次拍照圖片".jpg")
if (outputImage.exists())
outputImage.delete()
outputImage.createNewFile()
imageUri = if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
FileProvider.getUriForFile(this,"com.example.kotlin_demo.MainActivity",outputImage)
}else Uri.fromFile(outputImage)
intent1 = Intent("android.media.action.IMAGE_CAPTURE")
intent1.putExtra(MediaStore.EXTRA_OUTPUT,imageUri)
startActivityForResult(intent1,REQUEST_CODE)
}
xiangce.setOnClickListener{
dialog.dismiss()
REQUEST_CODE = 2
intent1 = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent1.addCategory(Intent.CATEGORY_OPENABLE)
intent1.type = "image/*"
startActivityForResult(intent1,REQUEST_CODE)
}
dialog.setContentView(inflate)
dialog.window?.apply {
setGravity(Gravity.BOTTOM) //設置Dialog從窗體底部彈出
setContentView(inflate)
attributes.height = 500
attributes.width = 1000
}
dialog.show()
}
窗口用的是Dialog
窗口的佈局文件R.layout.activity_second2很簡單,兩個按鈕,中間的一條橫線爲TextView
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:id="@+id/xiangce"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="相冊"
android:alpha="0.6"
android:background="#FFF"
android:textColor="#555555"
android:textStyle="bold"
android:textSize="15sp"
android:gravity="center"/>
<TextView
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#9e9e9e"/>
<Button
android:id="@+id/xiangji"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:textColor="#555555"
android:textStyle="bold"
android:background="#FFF"
android:text="打開相機拍照"
android:alpha="0.6"
android:textSize="15sp"
android:gravity="center"
/>
</LinearLayout>
新建文件路徑爲Environment.DIRECTORY_PICTURES,該地址爲手機Android/data/“包名”/files/Pictures,把圖片命名固定是爲了只保存一張最近拍照的圖片。
特別注意:區分Android7.0上下文件Uri的獲取方式
低於7.0直接用Uri的fromFile()方法
7.0開始直接使用本地真實路徑的Uri不安全,會有異常拋出,使用一種特殊的ContentProvider,FileProvider
要使用FileProvider還有兩步要做 :1、第一步 聲明FileProvider 2i、第二步 編寫XML文件 這兩步會寫在最後
3.點擊事件回調函數onActivityResult
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when(requestCode){
1->{ //相機事件
if (resultCode==Activity.RESULT_OK){
photoClip(imageUri)
}
}
2->{ //相冊事件
if (resultCode==Activity.RESULT_OK&&data!==null){
photoClip(data.data) //Intent.data爲被選取照片的uri地址
}
}
3->{
if (resultCode==Activity.RESULT_OK){
val bitmap = data?.extras?.get("data") as Bitmap
val path = saveImage("touxiang_"+System.currentTimeMillis(), bitmap)
path?.let {println("保存成功,圖片地址爲:$path")}
Glide.with(this).load(bitmap).override(250,250).into(main_imagV)
} else startActivityForResult(intent1,REQUEST_CODE)
}
}
}
調用第五步的方法saveImage保存圖片,第一個爲圖片名
圖片命名爲"touxiang_"+System.currentTimeMillis(),保存所有頭像圖片,防止名字重複
4.對照片進行裁剪
private fun photoClip(uri: Uri?) {
// 調用系統中自帶的圖片裁剪
val intent = Intent("com.android.camera.action.CROP")
intent.flags =
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
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("return-data", true)
startActivityForResult(intent, 3)
}
5.對裁剪後的頭像照片的保存
fun saveImage(name:String, bmp: Bitmap): String? {
val appDir = File (getExternalFilesDir(Environment.DIRECTORY_PICTURES).toString())
val fileName = name + ".jpg"
val file = File(appDir, fileName);
try {
val fos = FileOutputStream(file)
bmp.compress(Bitmap.CompressFormat.PNG,100, fos)
fos.flush()
fos.close()
return file.getAbsolutePath()
} catch (e:Exception) {
e.printStackTrace()
}
return null
}
6.在manifests文件中聲明FileProvider
爲什麼要聲明呢?
因爲FileProvider是ContentProvider子類
注意需要設置一個meta-data,裏面指向一個xml文件。
name值固定,android:authorities必須與剛剛FileProvider.getUriForFile()方法第二個參數一致
<provider
android:authorities="com.example.kotlin_demo.MainActivity"
android:name="androidx.core.content.FileProvider"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
7.編寫XML文件
爲什麼要寫這麼個xml文件?
因爲要使用content://uri替代file://uri,那麼,content://的uri如何定義呢?總不能使用文件路徑。
所以,需要一個虛擬的路徑對文件路徑進行映射,所以需要編寫個xml文件,通過path以及xml節點確定可訪問的目錄,通過name屬性來映射真實的文件路徑。name隨便填,path的/表示對整個sd卡進行共享
<paths>
<external-path
name = "photo"
path = "/"/>
</paths>
終於到最精彩的圖片展示環節