Kotlin高仿微信-第27篇-朋友圈-相册选择图片或小视频

news2024/11/24 13:23:11

 Kotlin高仿微信-项目实践58篇详细讲解了各个功能点,包括:注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。

Kotlin高仿微信-项目实践58篇,点击查看详情

效果图:

实现代码:

fun openAblum(){
    // 打开相册
    ImageSelector.builder()
        .useCamera(false) // 设置是否使用拍照
        .setSingle(false) //设置是否单选
        .canPreview(true) //是否点击放大图片查看,,默认为true
        .start(this,REQ_PICTURE_CODE)

}

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:id="@+id/rl_top_bar"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:background="#373c3d"
        android:orientation="vertical">

        <FrameLayout
            android:id="@+id/btn_back"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:foreground="@drawable/wc_btn_back_selector">

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:paddingLeft="10dp"
                android:paddingRight="10dp"
                android:scaleType="centerInside"
                android:src="@drawable/wc_base_back" />

        </FrameLayout>

        <FrameLayout
            android:id="@+id/btn_confirm"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginRight="16dp"
            android:foreground="@drawable/wc_btn_foreground_selector">

            <TextView
                android:id="@+id/tv_confirm"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/wc_blue_light_shape"
                android:gravity="center"
                android:minWidth="50dp"
                android:paddingLeft="5dp"
                android:paddingTop="5dp"
                android:paddingRight="5dp"
                android:paddingBottom="5dp"
                android:text="@string/selector_send"
                android:textColor="@android:color/white"
                android:textSize="14sp" />

        </FrameLayout>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="10dp"
            android:layout_toRightOf="@+id/btn_back"
            android:text="@string/selector_image"
            android:textColor="@android:color/white"
            android:textSize="18sp" />

        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/select_video"
            android:layout_width="wrap_content"
            android:layout_height="32dp"
            android:layout_centerInParent="true"
            android:background="@drawable/wc_base_green_selector"
            android:gravity="center"
            android:text="选择小视频"
            android:textColor="@color/white"
            android:textSize="12sp"
            android:textStyle="bold" />

        <View
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:layout_marginTop="12dp"
            android:layout_marginBottom="12dp"
            android:layout_toRightOf="@+id/btn_back"
            android:background="@android:color/black" />

    </RelativeLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/rl_bottom_bar"
        android:layout_below="@+id/rl_top_bar"
        android:background="#272828"
        android:fadingEdge="none"
        android:fadingEdgeLength="0dp"
        android:overScrollMode="never"
        android:scrollbars="vertical" />

    <TextView
        android:id="@+id/tv_time"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignTop="@+id/rv_image"
        android:background="#9e111212"
        android:paddingBottom="5dp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="5dp"
        android:textColor="@android:color/white"
        android:textSize="12sp" />

    <View
        android:id="@+id/masking"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignBottom="@+id/rv_image"
        android:layout_alignTop="@+id/rv_image"
        android:background="#c4111212"
        android:visibility="gone" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_folder"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignTop="@+id/rv_image"
        android:layout_alignBottom="@+id/rv_image"
        android:layout_marginTop="80dp"
        android:fadingEdge="none"
        android:fadingEdgeLength="0dp"
        android:overScrollMode="never"
        android:paddingTop="3dp"
        android:paddingBottom="3dp"
        android:scrollbars="vertical" />

    <RelativeLayout
        android:id="@+id/rl_bottom_bar"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:layout_alignParentBottom="true"
        android:background="#373c3d">

        <FrameLayout
            android:id="@+id/btn_folder"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_centerVertical="true"
            android:foreground="@drawable/wc_btn_foreground_selector">

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:paddingLeft="15dp"
                android:paddingRight="15dp">

                <TextView
                    android:id="@+id/tv_folder_name"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textColor="@android:color/white"
                    android:textSize="18sp" />

                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignBottom="@+id/tv_folder_name"
                    android:layout_marginLeft="2dp"
                    android:layout_toRightOf="@+id/tv_folder_name"
                    android:src="@drawable/text_indicator" />

            </RelativeLayout>

        </FrameLayout>

        <FrameLayout
            android:id="@+id/btn_preview"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentRight="true"
            android:foreground="@drawable/wc_btn_foreground_selector">

            <TextView
                android:id="@+id/tv_preview"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:gravity="center"
                android:minWidth="70dp"
                android:paddingLeft="12dp"
                android:paddingRight="12dp"
                android:text="@string/selector_preview"
                android:textColor="@android:color/white"
                android:textSize="18sp" />

        </FrameLayout>

        <View
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:layout_marginBottom="15dp"
            android:layout_marginTop="15dp"
            android:layout_toLeftOf="@+id/btn_preview"
            android:background="@android:color/black" />

    </RelativeLayout>
</RelativeLayout>

/**
 * author : wangning
 * email : maoning20080809@163.com
 * Date : 2022/4/15 16:44
 * description : 选择相册
 */
class ImageSelectorActivity : AppCompatActivity() {

    private var mAdapter: ImageAdapter? = null
    private var mLayoutManager: GridLayoutManager? = null

    private var mFolders: ArrayList<Folder>? = null
    private var mFolder: Folder? = null
    private var applyLoadImage = false
    private var applyCamera = false
    private val PERMISSION_WRITE_EXTERNAL_REQUEST_CODE = 0x00000011
    private val PERMISSION_CAMERA_REQUEST_CODE = 0x00000012

    private val CAMERA_REQUEST_CODE = 0x00000010
    private var mCameraUri: Uri? = null
    private var mCameraImagePath: String? = null
    private var mTakeTime: Long = 0

    private var isOpenFolder = false
    private var isShowTime = false
    private var isInitFolder = false
    private var isSingle = false
    private var canPreview = true
    private var mMaxCount = 0

    private var useCamera = true
    private var onlyTakePhoto = false

    private val mHideHandler = Handler()
    private val mHide = Runnable { hideTime() }

    //用于接收从外面传进来的已选择的图片列表。当用户原来已经有选择过图片,现在重新打开选择器,允许用
    // 户把先前选过的图片传进来,并把这些图片默认为选中状态。
    private var mSelectedImages: ArrayList<String>? = null

    private val REQ_VIDEO_CODE = 102


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val intent = intent
        val config: RequestConfig = intent.getParcelableExtra(ImageSelector.KEY_CONFIG)!!
        mMaxCount = config.maxSelectCount
        isSingle = config.isSingle
        canPreview = config.canPreview
        useCamera = config.useCamera
        mSelectedImages = config.selected
        onlyTakePhoto = config.onlyTakePhoto
        if (onlyTakePhoto) {
            // 仅拍照
            checkPermissionAndCamera()
        } else {
            setContentView(R.layout.wc_album_image_select)
            setStatusBarColor()
            initListener()
            initImageList()
            checkPermissionAndLoadImages()
            hideFolderList()
            setSelectImageCount(0)
        }
    }

    /**
     * 修改状态栏颜色
     */
    private fun setStatusBarColor() {
        if (VersionUtils.isAndroidL()) {
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
            window.statusBarColor = Color.parseColor("#373c3d")
        }
    }

    private fun initListener() {
        btn_back.setOnClickListener { finish() }
        btn_preview.setOnClickListener {
            val images = ArrayList<Image>()
            mAdapter?.getSelectImages()?.let { it -> images.addAll(it) }
            toPreviewActivity(images, 0)
        }
        //选择小视频
        select_video.setOnClickListener {
            val i = Intent(Intent.ACTION_PICK, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
            startActivityForResult(i, REQ_VIDEO_CODE)
        }
        btn_confirm.setOnClickListener { confirm() }
        btn_folder.setOnClickListener {
            if (isInitFolder) {
                if (isOpenFolder) {
                    closeFolder()
                } else {
                    openFolder()
                }
            }
        }
        masking.setOnClickListener { closeFolder() }
        rv_image.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                changeTime()
            }

            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                changeTime()
            }
        })
    }

    /**
     * 初始化图片列表
     */
    private fun initImageList() {
        // 判断屏幕方向
        val configuration = resources.configuration
        mLayoutManager = if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
            GridLayoutManager(this, 3)
        } else {
            GridLayoutManager(this, 5)
        }
        rv_image.layoutManager = mLayoutManager
        mAdapter = ImageAdapter(this, mMaxCount, isSingle, canPreview)
        rv_image.adapter = mAdapter
        (rv_image.itemAnimator as SimpleItemAnimator?)!!.supportsChangeAnimations = false
        if (mFolders != null && !mFolders!!.isEmpty()) {
            setFolder(mFolders!![0])
        }
        mAdapter?.setOnImageSelectListener(object : ImageAdapter.OnImageSelectListener {
            override fun onImageSelect(image: Image?, isSelect: Boolean, selectCount: Int) {
                setSelectImageCount(selectCount)
            }
        })
        mAdapter?.setOnItemClickListener(object : ImageAdapter.OnItemClickListener {

            override fun onItemClick(image: Image?, position: Int) {
                toPreviewActivity(mAdapter?.getData(), position)
            }

            override fun onCameraClick() {
                checkPermissionAndCamera()
            }
        })
    }

    /**
     * 初始化图片文件夹列表
     */
    private fun initFolderList() {
        if (mFolders != null && !mFolders!!.isEmpty()) {
            isInitFolder = true
            rv_folder.layoutManager = LinearLayoutManager(this@ImageSelectorActivity)
            val adapter = FolderAdapter(this@ImageSelectorActivity, mFolders)
            adapter.setOnFolderSelectListener(object : FolderAdapter.OnFolderSelectListener {
                override fun onFolderSelect(folder: Folder?) {
                    setFolder(folder)
                    closeFolder()
                }
            })
            rv_folder.adapter = adapter
        }
    }

    /**
     * 刚开始的时候文件夹列表默认是隐藏的
     */
    private fun hideFolderList() {
        rv_folder.post {
            rv_folder.translationY = rv_folder.height.toFloat()
            rv_folder.visibility = View.GONE
            rv_folder.setBackgroundColor(Color.WHITE)
        }
    }

    /**
     * 设置选中的文件夹,同时刷新图片列表
     * @param folder
     */
    private fun setFolder(folder: Folder?) {
        if (folder != null && mAdapter != null && !folder.equals(mFolder)) {
            mFolder = folder
            tv_folder_name.text = folder.getName()
            rv_image.scrollToPosition(0)
            mAdapter?.refresh(folder.getImages(), folder.isUseCamera())
        }
    }

    private fun setSelectImageCount(count: Int) {
        if (count == 0) {
            btn_confirm.isEnabled = false
            btn_preview.isEnabled = false
            tv_confirm.setText(R.string.selector_send)
            tv_preview.setText(R.string.selector_preview)
        } else {
            btn_confirm.isEnabled = true
            btn_preview.isEnabled = true
            tv_preview.text = getString(R.string.selector_preview) + "(" + count + ")"
            if (isSingle) {
                tv_confirm.setText(R.string.selector_send)
            } else if (mMaxCount > 0) {
                tv_confirm.text = getString(R.string.selector_send) + "(" + count + "/" + mMaxCount + ")"
            } else {
                tv_confirm.text = getString(R.string.selector_send) + "(" + count + ")"
            }
        }
    }

    /**
     * 弹出文件夹列表
     */
    @SuppressLint("ObjectAnimatorBinding")
    private fun openFolder() {
        if (!isOpenFolder) {
            masking.visibility = View.VISIBLE
            val animator = ObjectAnimator.ofFloat(rv_folder, "translationY",rv_folder.height.toFloat(), 0f).setDuration(300)
            animator.addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationStart(animation: Animator) {
                    super.onAnimationStart(animation)
                    rv_folder.visibility = View.VISIBLE
                }
            })
            animator.start()
            isOpenFolder = true
        }
    }

    /**
     * 收起文件夹列表
     */
    @SuppressLint("ObjectAnimatorBinding")
    private fun closeFolder() {
        if (isOpenFolder) {
            masking.visibility = View.GONE
            val animator = ObjectAnimator.ofFloat(rv_folder, "translationY", 0f, rv_folder.height.toFloat()).setDuration(300)
                animator.addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator) {
                    super.onAnimationEnd(animation)
                    rv_folder.visibility = View.GONE
                }
            })
            animator.start()
            isOpenFolder = false
        }
    }

    /**
     * 隐藏时间条
     */
    @SuppressLint("ObjectAnimatorBinding")
    private fun hideTime() {
        if (isShowTime) {
            ObjectAnimator.ofFloat(tv_time, "alpha", 1f, 0f).setDuration(300).start()
            isShowTime = false
        }
    }

    /**
     * 显示时间条
     */
    @SuppressLint("ObjectAnimatorBinding")
    private fun showTime() {
        if (!isShowTime) {
            ObjectAnimator.ofFloat(tv_time, "alpha", 0f, 1f).setDuration(300).start()
            isShowTime = true
        }
    }

    /**
     * 改变时间条显示的时间(显示图片列表中的第一个可见图片的时间)
     */
    private fun changeTime() {
        val firstVisibleItem = getFirstVisibleItem()
        val image: Image? = mAdapter?.getFirstVisibleImage(firstVisibleItem)
        if (image != null) {
            val time: String = DateUtils.getImageTime(this, image.getTime())
            tv_time.text = time
            showTime()
            mHideHandler.removeCallbacks(mHide)
            mHideHandler.postDelayed(mHide, 1500)
        }
    }

    private fun getFirstVisibleItem(): Int {
        return mLayoutManager!!.findFirstVisibleItemPosition()
    }

    private fun confirm() {
        if (mAdapter == null) {
            return
        }
        //因为图片的实体类是Image,而我们返回的是String数组,所以要进行转换。
        val selectImages: ArrayList<Image> = mAdapter?.getSelectImages()!!
        val images = ArrayList<String?>()
        for (image in selectImages) {
            images.add(image.getPath())
        }
        saveImageAndFinish(images, false)
    }

    private fun saveImageAndFinish(images: ArrayList<String?>, isCameraImage: Boolean) {
        //点击确定,把选中的图片通过Intent传给上一个Activity。
        setResult(images, isCameraImage)
        finish()
    }

    private fun setResult(images: ArrayList<String?>, isCameraImage: Boolean) {
        val intent = Intent()
        intent.putStringArrayListExtra(ImageSelector.SELECT_RESULT, images)
        intent.putExtra(ImageSelector.IS_CAMERA_IMAGE, isCameraImage)
        setResult(RESULT_OK, intent)
    }

    private fun toPreviewActivity(images: ArrayList<Image>?, position: Int) {
        if (images != null && !images.isEmpty()) {
            PreviewActivity.openActivity(this, images,mAdapter?.getSelectImages(), isSingle, mMaxCount, position)
        }
    }

    override fun onStart() {
        super.onStart()
        if (applyLoadImage) {
            applyLoadImage = false
            checkPermissionAndLoadImages()
        }
        if (applyCamera) {
            applyCamera = false
            checkPermissionAndCamera()
        }
    }

    /**
     * 处理图片预览页返回的结果
     *
     * @param requestCode
     * @param resultCode
     * @param data
     */
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == ImageSelector.RESULT_CODE) {
            if (data != null && data.getBooleanExtra(ImageSelector.IS_CONFIRM, false)) {
                //如果用户在预览页点击了确定,就直接把用户选中的图片返回给用户。
                confirm()
            } else {
                //否则,就刷新当前页面。
                mAdapter?.notifyDataSetChanged()
                setSelectImageCount(mAdapter?.getSelectImages()?.size!!)
            }
        } else if (requestCode == CAMERA_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                val images = ArrayList<String?>()
                var savePictureUri: Uri? = null
                if (VersionUtils.isAndroidQ()) {
                    savePictureUri = mCameraUri
                    images.add(UriUtils.getPathForUri(this, mCameraUri!!))
                } else {
                    savePictureUri = Uri.fromFile(File(mCameraImagePath))
                    images.add(mCameraImagePath)
                }
                ImageUtil.savePicture(this, savePictureUri, mTakeTime)
                saveImageAndFinish(images, true)
            } else {
                if (onlyTakePhoto) {
                    finish()
                }
            }
        } else if (requestCode == REQ_VIDEO_CODE && resultCode == RESULT_OK && null != data) {
            var selectedVideo = data.getData()!!
            var filePathColumn = arrayOf(MediaStore.Video.Media.DATA)
            var cursor : Cursor? = this.contentResolver.query(selectedVideo, filePathColumn, null, null, null)
            cursor?.moveToFirst()

            var columnIndex : Int? = cursor?.getColumnIndex(filePathColumn[0])
            var videoPath = cursor?.getString(columnIndex!!)
            cursor?.close()
            TagUtils.d("相册选择小视频路径:${videoPath}")
            /*var bundle = bundleOf(CommonUtils.Moments.TYPE_NAME to CommonUtils.Moments.TYPE_VIDEO, CommonUtils.Moments.TYPE_VIDEO_PATH to videoPath)
            navController?.navigate(R.id.action_moments_publish, bundle)*/
            var sVideoBean = SVideoBean(CommonUtils.Moments.TYPE_VIDEO, videoPath.toString())
            EventBus.getDefault().post(sVideoBean)
            finish()
        }
    }

    /**
     * 横竖屏切换处理
     * @param newConfig
     */
    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        if (mLayoutManager != null && mAdapter != null) {
            //切换为竖屏
            if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
                mLayoutManager!!.spanCount = 3
            } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
                mLayoutManager!!.spanCount = 5
            }
            mAdapter?.notifyDataSetChanged()
        }
    }

    /**
     * 检查权限并加载SD卡里的图片。
     */
    private fun checkPermissionAndLoadImages() {
        if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED) {
            Toast.makeText(this, "没有图片", Toast.LENGTH_LONG).show();
            return
        }
        val hasWriteExternalPermission = ContextCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE)
        if (hasWriteExternalPermission == PackageManager.PERMISSION_GRANTED) {
            //有权限,加载图片。
            loadImageForSDCard()
        } else {
            //没有权限,申请权限。
            ActivityCompat.requestPermissions(this@ImageSelectorActivity,arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),PERMISSION_WRITE_EXTERNAL_REQUEST_CODE)
        }
    }

    /**
     * 检查权限并拍照。
     */
    private fun checkPermissionAndCamera() {
        val hasCameraPermission =
            ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
        val hasWriteExternalPermission = ContextCompat.checkSelfPermission(
            this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
        )
        if (hasCameraPermission == PackageManager.PERMISSION_GRANTED
            && hasWriteExternalPermission == PackageManager.PERMISSION_GRANTED
        ) {
            //有调起相机拍照。
            openCamera()
        } else {
            //没有权限,申请权限。
            ActivityCompat.requestPermissions(
                this@ImageSelectorActivity,
                arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE),
                PERMISSION_CAMERA_REQUEST_CODE
            )
        }
    }

    /**
     * 处理权限申请的回调。
     *
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        if (requestCode == PERMISSION_WRITE_EXTERNAL_REQUEST_CODE) {
            if (grantResults.size > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED
            ) {
                //允许权限,加载图片。
                loadImageForSDCard()
            } else {
                //拒绝权限,弹出提示框。
                showExceptionDialog(true)
            }
        } else if (requestCode == PERMISSION_CAMERA_REQUEST_CODE) {
            if (grantResults.size > 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                //允许权限,有调起相机拍照。
                openCamera()
            } else {
                //拒绝权限,弹出提示框。
                showExceptionDialog(false)
            }
        }
    }

    /**
     * 发生没有权限等异常时,显示一个提示dialog.
     */
    private fun showExceptionDialog(applyLoad: Boolean) {
        AlertDialog.Builder(this)
            .setCancelable(false)
            .setTitle(R.string.selector_hint)
            .setMessage(R.string.selector_permissions_hint)
            .setNegativeButton(R.string.selector_cancel,
                DialogInterface.OnClickListener { dialog, which ->
                    dialog.cancel()
                    finish()
                }).setPositiveButton(R.string.selector_confirm,
                DialogInterface.OnClickListener { dialog, which ->
                    dialog.cancel()
                    startAppSettings()
                    if (applyLoad) {
                        applyLoadImage = true
                    } else {
                        applyCamera = true
                    }
                }).show()
    }

    /**
     * 从SDCard加载图片。
     */
    private fun loadImageForSDCard() {
        ImageModel.loadImageForSDCard(this, object : ImageModel.Companion.DataCallback{
            override fun onSuccess(folders: ArrayList<Folder>?) {
                mFolders = folders
                runOnUiThread {
                    if (mFolders != null && !mFolders!!.isEmpty()) {
                        initFolderList()
                        mFolders!![0].setUseCamera(useCamera)
                        setFolder(mFolders!![0])
                        if (mSelectedImages != null && mAdapter != null) {
                            mAdapter?.setSelectedImages(mSelectedImages)
                            mSelectedImages = null
                            setSelectImageCount(mAdapter?.getSelectImages()?.size!!)
                        }
                    }
                }
            }
        })
    }

    /**
     * 调起相机拍照
     */
    private fun openCamera() {
        val captureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        if (captureIntent.resolveActivity(packageManager) != null) {
            var photoFile: File? = null
            var photoUri: Uri? = null
            if (VersionUtils.isAndroidQ()) {
                photoUri = createImagePathUri()
            } else {
                try {
                    photoFile = createImageFile()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
                if (photoFile != null) {
                    mCameraImagePath = photoFile.absolutePath
                    photoUri = if (VersionUtils.isAndroidN()) {
                        //通过FileProvider创建一个content类型的Uri
                        FileProvider.getUriForFile(this, "$packageName.fileProvider", photoFile)
                    } else {
                        Uri.fromFile(photoFile)
                    }
                }
            }
            mCameraUri = photoUri
            if (photoUri != null) {
                captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri)
                captureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                startActivityForResult(captureIntent, CAMERA_REQUEST_CODE)
                mTakeTime = System.currentTimeMillis()
            }
        }
    }

    /**
     * 创建一条图片地址uri,用于保存拍照后的照片
     * @return 图片的uri
     */
    fun createImagePathUri(): Uri? {
        val status = Environment.getExternalStorageState()
        val timeFormatter = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault())
        val time = System.currentTimeMillis()
        val imageName = timeFormatter.format(Date(time))
        // ContentValues是我们希望这条记录被创建时包含的数据信息
        val values = ContentValues(2)
        values.put(MediaStore.Images.Media.DISPLAY_NAME, imageName)
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
        // 判断是否有SD卡,优先使用SD卡存储,当没有SD卡时使用手机存储
        return if (status == Environment.MEDIA_MOUNTED) {
            contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
        } else {
            contentResolver.insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, values)
        }
    }

    @Throws(IOException::class)
    private fun createImageFile(): File? {
        val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
        val imageFileName = String.format("JPEG_%s.jpg", timeStamp)
        val storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
        if (!storageDir.exists()) {
            storageDir.mkdir()
        }
        val tempFile = File(storageDir, imageFileName)
        return if (Environment.MEDIA_MOUNTED != EnvironmentCompat.getStorageState(tempFile)) {
            null
        } else tempFile
    }

    /**
     * 启动应用的设置
     */
    private fun startAppSettings() {
        val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
        intent.data = Uri.parse("package:$packageName")
        startActivity(intent)
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_DOWN && isOpenFolder) {
            closeFolder()
            return true
        }
        return super.onKeyDown(keyCode, event)
    }

    companion object {
        /**
         * 启动图片选择器
         * @param activity
         * @param requestCode
         * @param config
         */
        fun openActivity(activity: Activity, requestCode: Int, config: RequestConfig?) {
            val intent = Intent(activity, ImageSelectorActivity::class.java)
            intent.putExtra(ImageSelector.KEY_CONFIG, config)
            activity.startActivityForResult(intent, requestCode)
        }

        /**
         * 启动图片选择器
         * @param fragment
         * @param requestCode
         * @param config
         */
        fun openActivity(fragment: Fragment, requestCode: Int, config: RequestConfig?) {
            val intent = Intent(fragment.activity, ImageSelectorActivity::class.java)
            intent.putExtra(ImageSelector.KEY_CONFIG, config)
            fragment.startActivityForResult(intent, requestCode)
        }

        /**
         * 启动图片选择器
         * @param fragment
         * @param requestCode
         * @param config
         */
        fun openActivity(fragment: android.app.Fragment, requestCode: Int, config: RequestConfig?) {
            val intent = Intent(fragment.activity, ImageSelectorActivity::class.java)
            intent.putExtra(ImageSelector.KEY_CONFIG, config)
            fragment.startActivityForResult(intent, requestCode)
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/51009.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ContentProvider启动流程分析

文章目录1.ActivityThread.handleBindApplication()2.ActivityThread.installContentProviders()3.ActivityThread.installProvider()4.AppComponentFactory.instantiateProvider()5.ActivityManagerService.publishContentProviders()6.ContentProviderHelper.publishContentP…

基于Web的美食分享平台的设计与实现——HTML+CSS+JavaScript水果介绍网页设计(橙子之家)

&#x1f468;‍&#x1f393;静态网站的编写主要是用HTML DIVCSS JS等来完成页面的排版设计&#x1f469;‍&#x1f393;,常用的网页设计软件有Dreamweaver、EditPlus、HBuilderX、VScode 、Webstorm、Animate等等&#xff0c;用的最多的还是DW&#xff0c;当然不同软件写出的…

[附源码]计算机毕业设计springboot汽车租赁管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

项目的坎坷一生

一、从产品到项目 项目的定义&#xff1a;只会进行一次&#xff0c;包含多项互相关联的任务&#xff0c;并且有绩效、时间、成本和范围限制的一项工作。 产品是解决某个问题的东西&#xff0c;项目是一个过程。 1、做产品VS做项目 ①从生命周期角度区别 做产品的生命周期相…

[附源码]JAVA毕业设计的问卷调查系统设计与实现(系统+LW)

[附源码]JAVA毕业设计的问卷调查系统设计与实现&#xff08;系统LW&#xff09; 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 …

dreamweaver网页设计作业制作 学生个人网页猫眼电影 WEB静态网页作业模板 大学生个人主页博客网页代码 dw个人网页作业成品

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 文章目录一、网页介绍一…

高校房产管理系统应具备哪些基本功能?

数图互通经过多年高校房产管理实施认为高校房产管理系统应用层面应具备的基本功能如下&#xff1a; 1、框架平台&#xff08;含系统管理、系统接口&#xff09; 框架平台包含系统权限管理、用户管理、角色管理、菜单管理、VPA数据权限管理、数据字典管理、系统日志管理、数据…

jsp汽车销售管理软件Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 jsp汽车销售管理软件 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql&#xff0c;使用…

证券企业基于华为全闪存存储实践经验分享

【导读】本文结合华为存储相关最佳实践和证券公司长期使用多厂商的全闪存存储的实践经验进行总结分享,内容包括:剖析存储发展过程中遇到难题、使用华为中端全闪存存储架构分析、项目中存储规划说明、全闪存存储实践经验总结等。希望能对券商同行存储架构选型实践等提供参考借…

关于input的一些事件和属性

disabled和readonly两者的联系&#xff1a; 1、两个属性都可以作用于input等表单元素上&#xff0c;都使得元素成为“不可用”的状态&#xff1b; 2、两者的字面意义&#xff1a; &#xff08;1&#xff09;readonly表示“只读”&#xff0c;一般表示对于文字内容只读&#xf…

Android 开源一个USB读写demo,从多个USB设备中选择一个实现外设控制的通信

CSDN 下载链接https://download.csdn.net/download/gao511147456/87226599 如果你不想下载可以阅读下面教程并复制代码 运行视频 device-2022-11-27-231324AndroidManifest <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android&qu…

数仓常用排序详解

目录 order by&#xff1a;全局排序 sort by&#xff1a;局部排序 cluster by&#xff1a;簇排序 group by partition by order by&#xff1a;全局排序 order by 会对数据进行一次全局排序&#xff0c;所以说&#xff0c;只要hive的sql中指定了order by&#xff0c;那么…

二、【React拓展】懒加载 lazy

文章目录1、适用点2、汇总1、适用点 懒加载往往配合路由一起使用&#xff0c;此处修改的项目是 二、【React-Router5】路由的基本使用 中的项目 首先从react中引入lazy import { lazy } from react 修改引入路由组件的写法 // import About from ./pages/About // import Home…

[附源码]Python计算机毕业设计Django房屋租赁信息系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

[附源码]Python计算机毕业设计SSM-乐室预约小程序(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

数字化下烟草行业人力资源管理实践与思考

“十四五”期间&#xff0c;高质量发展要求提质增效、科技创新、转型升级、数字化发展&#xff1b;在政府的工作报告中“创新”、“增长”、“机制”这些词不断提及&#xff0c;企业的发展重点也逐渐由高增长变为高质量发展。烟草行业如何对标世界一流管理&#xff0c;促进人力…

人工智能、机器学习概述

一、人工智能简单了解 1.人工智能发展必备三要素&#xff1a; 数据算法计算力 CPU,GPU,TPU计算力之CPU、GPU对比&#xff1a; CPU主要适合I\O密集型的任务 GPU主要适合计算密集型任务 2.人工智能、机器学习和深度学习 人工智能和机器学习&#xff0c;深度学习的关系 机器学…

野火FPGA进阶(2):基于I2C协议的EEPROM驱动控制

文章目录第49讲&#xff1a;基于I2C协议的EEPROM驱动控制理论部分设计与实现i2c_ctrli2c_rw_dataeeprom_byte_rd_wrtb_eeprom_byte_rd_wr第49讲&#xff1a;基于I2C协议的EEPROM驱动控制 理论部分 I2C通讯协议&#xff08;Inter-Integrated Circuit&#xff09;是由Philips公…

Flume环境搭建

1、新建一个专门放文件的目录&#xff1a;mkdir /export/server 2、将Flume的安装包上传到/export/server目录并解压&#xff0c;重命名&#xff1a; tar -zxvf apache-flume-1.8.0-bin.tar.gz -C /export/server mv apache-flume-1.8.0-bin flume 3、修改flume-env.sh文件…

[附源码]计算机毕业设计JAVA校园飞毛腿系统

[附源码]计算机毕业设计JAVA校园飞毛腿系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis …