效果图:
核心代码:
清单文件里写上权限:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.uploadpictures">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
tools:ignore="GoogleAppIndexingWarning"
android:theme="@style/AppTheme">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.uploadpictures.fileprovider"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
动态请求权限使用RxPermissions,以及用RxView防抖,弹框使用MaterialDialog
RxView.clicks(addPictureTv)
.throttleFirst(2, TimeUnit.SECONDS)
.compose(
RxPermissions(this@MainActivity)
.ensure(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
)
)
.subscribe {
if (it) {
if (!isDestroyed) {
MaterialDialog(mContext)
.title(text = "请选择")
.cancelable(true)
.show {
listItems(
items = mutableListOf(
"拍照",
"相册"
)
) { dialog, index, text ->
if (text == "拍照") {
takePhoto()
} else {
takeGallery()
}
}
}
}
} else {
Toast.makeText(this@MainActivity, "缺少拍照或存储权限,请到设置中开启后使用", Toast.LENGTH_SHORT)
.show()
}
}
核心代码:
class MainActivity : AppCompatActivity() {
companion object {
const val REQUEST_CODE_TAKE_PHOTO = 101
const val REQUEST_CODE_PICK_PHOTO = 102
}
private lateinit var pictures: MutableList<Picture>
private lateinit var pictureAdapter: BaseQuickAdapter<Picture, BaseViewHolder>
//图片
private var currentPictureUri: Uri? = null
private var currentPictureFile: File? = null
private val pictureAddressSet = mutableSetOf<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initListener()
pictures = mutableListOf(Picture())
pictureAdapter =
object : BaseQuickAdapter<Picture, BaseViewHolder>(R.layout.item_suggestion_picture) {
override fun convert(helper: BaseViewHolder, item: Picture?) {
helper.apply {
val pictureIv = getView<ImageView>(R.id.iv_picture)
val deleteIv = getView<ImageView>(R.id.iv_delete)
val addPictureTv = getView<TextView>(R.id.tv_add_picture)
val contentCl = getView<ConstraintLayout>(R.id.cl_content)
contentCl.layoutParams = ConstraintLayout.LayoutParams(
windowManager.defaultDisplay.width / 4,
windowManager.defaultDisplay.width / 4
)
if (item?.uri == null) {
//添加图片
deleteIv.visibility = View.GONE
pictureIv.visibility = View.GONE
addPictureTv.visibility = View.VISIBLE
RxView.clicks(addPictureTv)
.throttleFirst(2, TimeUnit.SECONDS)
.compose(
RxPermissions(this@MainActivity)
.ensure(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
)
)
.subscribe {
if (it) {
if (!isDestroyed) {
MaterialDialog(mContext)
.title(text = "请选择")
.cancelable(true)
.show {
listItems(
items = mutableListOf(
"拍照",
"相册"
)
) { dialog, index, text ->
if (text == "拍照") {
takePhoto()
} else {
takeGallery()
}
}
}
}
} else {
Toast.makeText(this@MainActivity,"缺少拍照或存储权限,请到设置中开启后使用",Toast.LENGTH_SHORT).show()
}
}
} else {
//显示图片
deleteIv.visibility = View.VISIBLE
pictureIv.visibility = View.VISIBLE
addPictureTv.visibility = View.GONE
Glide.with(this@MainActivity).load(item.uri).into(pictureIv)
deleteIv.setOnClickListener {
pictures.removeAt(adapterPosition)
tv_picture_num.text = "(${pictures.size - 1}/5)"
notifyDataSetChanged()
}
}
}
}
override fun getItemCount(): Int {
return if (pictures.size > 5) {
5
} else {
pictures.size
}
}
}
recyclerview.apply {
layoutManager = GridLayoutManager(this@MainActivity, 4, RecyclerView.VERTICAL, false)
adapter = pictureAdapter
}
pictureAdapter.setNewData(pictures)
}
private fun initListener() {
tv_submit.setOnClickListener {
submit()
}
}
private fun submit() {
//加载框
pictureAddressSet.clear()
//1.循环将图片上传服务器
if (pictures.size > 1) {
pictures.filter { it.file != null }
.forEach {
val outFilePath =
getExternalFilesDir(null)?.absolutePath + File.separator + System.currentTimeMillis() + "temp.jpg"
val requestBody = it.uri!!
.copyAndConvert(this, outFilePath)
.asRequestBody("multipart/form-data".toMediaTypeOrNull())
val part = MultipartBody.Part.createFormData("file", it.file?.name, requestBody)
//网络请求,把图片上传
mViewModel.uploadFile(part)
}
}
}
override fun startObserve() {
super.startObserve()
//2.图片提交成功
uploadFileSuccess.observe(this@MainActivity, androidx.lifecycle.Observer {
pictureAddressSet.add(it.fileUrl)
if (pictureAddressSet.size == pictures.size - 1) {
orderOutsideHotelRequest?.fileKeys = pictureAddressSet.toMutableList()
//3.图片上传完以后再走提交操作
mViewModel.createReimbursement(orderOutsideHotelRequest!!)
}
})
}
/**
* 相册
*/
private fun takeGallery() {
val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
intent.type = "image/*"
startActivityForResult(intent, REQUEST_CODE_PICK_PHOTO)
}
/**
* 拍照
*/
private fun takePhoto() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (takePictureIntent.resolveActivity(packageManager) != null) {
val fileName = "${SimpleDateFormat("yyyyMMdd-HHmmss", Locale.CHINA).format(Date())}.png"
val photoFile = File(getExternalFilesDir(null), fileName)
currentPictureFile = photoFile
currentPictureUri = FileProviderForAPI24.getUriForFile(this, photoFile)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, currentPictureUri)
startActivityForResult(takePictureIntent, REQUEST_CODE_TAKE_PHOTO)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
REQUEST_CODE_TAKE_PHOTO -> {
val picture = Picture()
picture.file = currentPictureFile
picture.uri = currentPictureUri
pictures.add(pictures.size - 1, picture)
pictureAdapter.notifyDataSetChanged()
tv_picture_num.text = "(${pictures.size - 1}/5)"
}
REQUEST_CODE_PICK_PHOTO -> {
currentPictureUri = data?.data
currentPictureUri?.apply {
val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
val cursor = contentResolver.query(
currentPictureUri!!,
filePathColumn,
null,
null,
null
)
cursor?.moveToFirst()
val path =
cursor?.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA))
cursor?.close()
currentPictureFile = File(path)
val picture = Picture()
picture.file = currentPictureFile
picture.uri = currentPictureUri
pictures.add(pictures.size - 1, picture)
pictureAdapter.notifyDataSetChanged()
tv_picture_num.text = "(${pictures.size - 1}/5)"
}
}
}
}
}
}
class Picture {
var uri: Uri? = null
var file: File? = null
}
网络请求部分我没有加进去,逻辑大体这样。
源码地址:https://download.csdn.net/download/jingerlovexiaojie/18622427