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為1outputImage = 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 = 2intent1 = 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 = 500attributes.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"><Buttonandroid: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"/><TextViewandroid:layout_width="match_parent"android:layout_height="1dp"android:background="#9e9e9e"/><Buttonandroid: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 Bitmapval 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_PERMISSIONintent.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)//將bitmap圖片壓縮輸出到輸出流對應uri地址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()方法第二個參數一致
7.編寫XML文件
為什么要寫這么個xml文件?
因為要使用content://uri替代file://uri,那么,content://的uri如何定義呢?總不能使用文件路徑。
所以,需要一個虛擬的路徑對文件路徑進行映射,所以需要編寫個xml文件,通過path以及xml節點確定可訪問的目錄,通過name屬性來映射真實的文件路徑。name隨便填,path的/表示對整個sd卡進行共享
終于到最精彩的圖片展示環節
? ? ? ? ? ? ? ? ??? ? ? ? ? ? ? ? ??
作用域存儲:
Android系統對SD卡的使用做了很大的限制。從Android 10開始,每個應用程序只能有權在自己的外置存儲空間關聯目錄下讀取和創建文件,獲取該關聯目錄的代碼是:context.getExternalFilesDir()。關聯目錄對應的路徑大致如下:
/storage/emulated/0/Android/data/<包名>/files這個目錄中的文件會被計入到應用程序的占用空間當中,同時也會隨著應用程序的卸載而被刪除。?
訪問其他目錄該怎么辦呢?比如讀取手機相冊中的圖片,或者向手機相冊中添加一張圖片。為此,Android系統針對文件類型進行了分類,圖片、音頻、視頻這三類文件將可以通過MediaStore API來進行訪問,而其他類型的文件則需要使用系統的文件選擇器來進行訪問。
在作用域存儲當中,我們只能借助MediaStore API獲取到圖片的Uri,示例代碼如下:
val cursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, "${MediaStore.MediaColumns.DATE_ADDED} desc") if (cursor != null) {while (cursor.moveToNext()) {val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID))val uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)println("image uri is $uri")}cursor.close() }將網絡上的圖片存儲到手機相冊當中?
fun writeInputStreamToAlbum(inputStream: InputStream, displayName: String, mimeType: String) {val values = ContentValues()values.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName)values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType)if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM)} else {values.put(MediaStore.MediaColumns.DATA, "${Environment.getExternalStorageDirectory().path}/${Environment.DIRECTORY_DCIM}/$displayName")}val bis = BufferedInputStream(inputStream)val uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)if (uri != null) {val outputStream = contentResolver.openOutputStream(uri)if (outputStream != null) {val bos = BufferedOutputStream(outputStream)val buffer = ByteArray(1024)var bytes = bis.read(buffer)while (bytes >= 0) {bos.write(buffer, 0 , bytes)bos.flush()bytes = bis.read(buffer)}bos.close()}}bis.close() }?
總結
以上是生活随笔為你收集整理的Android—显示窗口调用相机与相册的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 通过人行横道线
- 下一篇: android sina oauth2.