Android—顯示窗口調用相機與相冊

關於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>

終於到最精彩的圖片展示環節

                                    

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章