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)
}
}
}


![[附源码]计算机毕业设计springboot汽车租赁管理系统](https://img-blog.csdnimg.cn/82b1f305fd5f4a758e928c18c25e3809.png)

![[附源码]JAVA毕业设计的问卷调查系统设计与实现(系统+LW)](https://img-blog.csdnimg.cn/0c4dd055e93449f0b43bc900526ab768.png)








![[附源码]Python计算机毕业设计Django房屋租赁信息系统](https://img-blog.csdnimg.cn/56a2fa548ad54dbda92fc67a25d628f7.png)
![[附源码]Python计算机毕业设计SSM-乐室预约小程序(程序+LW)](https://img-blog.csdnimg.cn/a4792969146147b783f6cabf29bd7437.png)




![[附源码]计算机毕业设计JAVA校园飞毛腿系统](https://img-blog.csdnimg.cn/47173add29db4886bc31516ee0944517.png)