增加任务无mark校验及关闭业务

This commit is contained in:
qiji4215 2023-07-04 10:08:47 +08:00
parent 5e32c7ac8e
commit e3a78aeb77
11 changed files with 697 additions and 135 deletions

View File

@ -137,11 +137,6 @@ class TaskUploadScope(
problemType = 2 problemType = 2
} }
var evaluationWay = 2 var evaluationWay = 2
/* if(it.evaluationWay=="生产测评"){
evaluationWay = "1"
}else if(it.evaluationWay=="现场测评"){
evaluationWay = "2"
}*/
val evaluationInfo = EvaluationInfo( val evaluationInfo = EvaluationInfo(
evaluationTaskId = taskBean.id.toString(), evaluationTaskId = taskBean.id.toString(),
linkPid = hadLinkDvoBean.linkPid,//"84207223282277331" linkPid = hadLinkDvoBean.linkPid,//"84207223282277331"

View File

@ -28,6 +28,7 @@ class FileManager {
const val ERROR = 2 //错误 const val ERROR = 2 //错误
const val WAITING = 3 //等待中 const val WAITING = 3 //等待中
const val UPLOADING = 4 //同步中 const val UPLOADING = 4 //同步中
const val NOUPLOAD = 5 //无能上传
} }
//初始化数据文件夹 //初始化数据文件夹

View File

@ -2,9 +2,13 @@ package com.navinfo.omqs.ui.fragment
import android.os.Bundle import android.os.Bundle
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.google.android.material.R
import com.google.android.material.dialog.MaterialAlertDialogBuilder
abstract class BaseFragment : Fragment() { abstract class BaseFragment : Fragment() {
private var loadingDialog: AlertDialog? = null
// override fun onCreateView( // override fun onCreateView(
// inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? // inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
// ): View { // ): View {
@ -49,4 +53,21 @@ abstract class BaseFragment : Fragment() {
return true return true
} }
/**
* 显示loading dialog
*/
fun showLoadingDialog(message: String) {
loadingDialog?.dismiss()
loadingDialog = MaterialAlertDialogBuilder(
this.requireContext(), R.style.MaterialAlertDialog_Material3_Animation).setMessage(message).setCancelable(false).show()
}
/**
* 隐藏loading dialog
* */
fun hideLoadingDialog() {
loadingDialog?.dismiss()
loadingDialog = null
}
} }

View File

@ -1,5 +1,7 @@
package com.navinfo.omqs.ui.fragment.tasklist package com.navinfo.omqs.ui.fragment.tasklist
import android.annotation.SuppressLint
import android.app.Dialog
import android.graphics.Color import android.graphics.Color
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
@ -7,15 +9,25 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.recyclerview.widget.RecyclerView
import com.navinfo.collect.library.data.entity.QsRecordBean
import com.navinfo.collect.library.data.entity.TaskBean import com.navinfo.collect.library.data.entity.TaskBean
import com.navinfo.omqs.R import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.AdapterTaskListBinding import com.navinfo.omqs.databinding.AdapterTaskListBinding
import com.navinfo.omqs.http.taskdownload.TaskDownloadManager import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
import com.navinfo.omqs.http.taskupload.TaskUploadManager import com.navinfo.omqs.http.taskupload.TaskUploadManager
import com.navinfo.omqs.tools.FileManager
import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
import com.navinfo.omqs.tools.FileManager.Companion.FileUploadStatus import com.navinfo.omqs.tools.FileManager.Companion.FileUploadStatus
import com.navinfo.omqs.ui.dialog.FirstDialog
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
import com.navinfo.omqs.ui.other.BaseViewHolder import com.navinfo.omqs.ui.other.BaseViewHolder
import com.navinfo.omqs.ui.widget.LeftDeleteView
import io.realm.Realm
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/** /**
* 离线地图城市列表 RecyclerView 适配器 * 离线地图城市列表 RecyclerView 适配器
@ -28,10 +40,17 @@ import com.navinfo.omqs.ui.other.BaseViewHolder
class TaskListAdapter( class TaskListAdapter(
private val downloadManager: TaskDownloadManager, private val downloadManager: TaskDownloadManager,
private val uploadManager: TaskUploadManager, private val uploadManager: TaskUploadManager,
private var itemListener: ((Int, TaskBean) -> Unit?)? = null private val recyclerView: RecyclerView,
private var itemListener: ((Int, Int, TaskBean) -> Unit?)? = null,
) : BaseRecyclerViewAdapter<TaskBean>() { ) : BaseRecyclerViewAdapter<TaskBean>() {
private var selectPosition = -1 private var selectPosition = -1
private var leftDeleteView: LeftDeleteView? = null
private val mRecyclerView = recyclerView
private var isShowDeleteView = false
private private
val downloadBtnClick = View.OnClickListener() { val downloadBtnClick = View.OnClickListener() {
if (it.tag != null) { if (it.tag != null) {
@ -50,29 +69,55 @@ class TaskListAdapter(
} }
} }
} else { } else {
Toast.makeText(downloadManager.context, "数据错误无Link信息无法执行下载", Toast.LENGTH_LONG).show() Toast.makeText(
downloadManager.context,
"数据错误无Link信息无法执行下载",
Toast.LENGTH_LONG
).show()
} }
} }
} }
private val uploadBtnClick = View.OnClickListener() { private val uploadBtnClick = View.OnClickListener() {
if (it.tag != null) { if (it.tag != null) {
val taskBean = data[it.tag as Int] val taskBean = data[it.tag as Int]
if (taskBean.hadLinkDvoList.isNotEmpty()) { if (taskBean.hadLinkDvoList.isNotEmpty()) {
when (taskBean.syncStatus) {
FileUploadStatus.NONE, FileUploadStatus.UPLOADING, FileUploadStatus.ERROR, FileUploadStatus.WAITING -> { itemListener?.invoke(it.tag as Int, ItemClickStatus.UPLOAD_LAYOUT_CLICK, taskBean)
uploadManager.start(taskBean.id)
} } else {
} Toast.makeText(
}else{ uploadManager.context,
Toast.makeText(uploadManager.context, "数据错误无Link信息无法执行同步", Toast.LENGTH_LONG).show() "数据错误无Link信息无法执行同步",
Toast.LENGTH_LONG
).show()
}
}
}
/**
* 重置item状态
* @param point
*/
fun uploadTask(taskBean: TaskBean) {
when (taskBean.syncStatus) {
FileManager.Companion.FileUploadStatus.NONE, FileManager.Companion.FileUploadStatus.UPLOADING, FileManager.Companion.FileUploadStatus.ERROR, FileManager.Companion.FileUploadStatus.WAITING -> {
uploadManager.start(taskBean.id)
} }
} }
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
val viewBinding = val viewBinding =
AdapterTaskListBinding.inflate(LayoutInflater.from(parent.context), parent, false) AdapterTaskListBinding.inflate(LayoutInflater.from(parent.context), parent, false)
val deleteView = viewBinding.root
deleteView.setRecyclerView(mRecyclerView)
return BaseViewHolder(viewBinding) return BaseViewHolder(viewBinding)
} }
@ -82,10 +127,25 @@ class TaskListAdapter(
downloadManager.removeObserver(holder.tag.toInt()) downloadManager.removeObserver(holder.tag.toInt())
} }
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) { override fun onBindViewHolder(
holder: BaseViewHolder,
@SuppressLint("RecyclerView") position: Int
) {
val binding: AdapterTaskListBinding = val binding: AdapterTaskListBinding =
holder.viewBinding as AdapterTaskListBinding holder.viewBinding as AdapterTaskListBinding
val taskBean = data[position] val taskBean = data[position]
binding.root.mStatusChangeLister = {
isShowDeleteView = it
if (it) {
//重置以后滑动布局
restoreItemView()
// 如果编辑菜单在显示
leftDeleteView = binding.root
selectPosition = position
} else {
selectPosition = -1
}
}
//tag 方便onclick里拿到数据 //tag 方便onclick里拿到数据
holder.tag = taskBean.id.toString() holder.tag = taskBean.id.toString()
changeViews(binding, taskBean) changeViews(binding, taskBean)
@ -122,18 +182,40 @@ class TaskListAdapter(
binding.taskCityName.text = taskBean.cityName binding.taskCityName.text = taskBean.cityName
binding.taskDataVersion.text = "版本号:${taskBean.dataVersion}" binding.taskDataVersion.text = "版本号:${taskBean.dataVersion}"
binding.root.isSelected = selectPosition == position binding.root.isSelected = selectPosition == position
binding.root.setOnClickListener {
val pos = holder.adapterPosition
if (selectPosition != pos) {
val lastPos = selectPosition
selectPosition = pos
if (lastPos > -1) {
notifyItemChanged(lastPos)
}
binding.root.isSelected = true
itemListener?.invoke(position, taskBean)
}
binding.taskItemLayout.setOnClickListener {
if (isShowDeleteView) {
leftDeleteView?.resetDeleteStatus()
} else {
val pos = holder.adapterPosition
if (selectPosition != pos) {
val lastPos = selectPosition
selectPosition = pos
if (lastPos > -1) {
notifyItemChanged(lastPos)
}
binding.root.isSelected = true
itemListener?.invoke(position, ItemClickStatus.ITEM_LAYOUT_CLICK, taskBean)
}
}
}
binding.taskDeleteLayout.setOnClickListener {
//重置状态
leftDeleteView?.resetDeleteStatus()
itemListener?.invoke(position, ItemClickStatus.DELETE_LAYOUT_CLICK, taskBean)
}
}
/**
* 重置item状态
* @param point
*/
fun restoreItemView() {
leftDeleteView?.let {
if (isShowDeleteView)
it.resetDeleteStatus()
} }
} }
@ -271,7 +353,8 @@ class TaskListAdapter(
} }
val errMsg = taskBean.errMsg val errMsg = taskBean.errMsg
if (errMsg != null && errMsg.isNotEmpty()) { if (errMsg != null && errMsg.isNotEmpty()) {
Toast.makeText(binding.taskProgressText.context, errMsg, Toast.LENGTH_LONG).show() Toast.makeText(binding.taskProgressText.context, errMsg, Toast.LENGTH_LONG)
.show()
} }
} }
@ -282,6 +365,14 @@ class TaskListAdapter(
} }
} }
} }
companion object {
object ItemClickStatus {
const val ITEM_LAYOUT_CLICK = 0 //条目点击
const val DELETE_LAYOUT_CLICK = 1 //删除点击
const val UPLOAD_LAYOUT_CLICK = 2 //上传点击
}
}
} }

View File

@ -1,5 +1,7 @@
package com.navinfo.omqs.ui.fragment.tasklist package com.navinfo.omqs.ui.fragment.tasklist
import android.app.Dialog
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
@ -7,15 +9,26 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.navinfo.collect.library.data.entity.QsRecordBean
import com.navinfo.collect.library.data.entity.TaskBean
import com.navinfo.omqs.databinding.FragmentTaskListBinding import com.navinfo.omqs.databinding.FragmentTaskListBinding
import com.navinfo.omqs.http.taskdownload.TaskDownloadManager import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
import com.navinfo.omqs.http.taskupload.TaskUploadManager import com.navinfo.omqs.http.taskupload.TaskUploadManager
import com.navinfo.omqs.tools.FileManager
import com.navinfo.omqs.ui.dialog.FirstDialog
import com.navinfo.omqs.ui.fragment.BaseFragment import com.navinfo.omqs.ui.fragment.BaseFragment
import com.navinfo.omqs.ui.other.shareViewModels import com.navinfo.omqs.ui.other.shareViewModels
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import io.realm.Realm
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject import javax.inject.Inject
@RequiresApi(Build.VERSION_CODES.M)
@AndroidEntryPoint @AndroidEntryPoint
class TaskListFragment : BaseFragment() { class TaskListFragment : BaseFragment() {
@ -31,14 +44,25 @@ class TaskListFragment : BaseFragment() {
*/ */
private val viewModel by shareViewModels<TaskViewModel>("Task") private val viewModel by shareViewModels<TaskViewModel>("Task")
private val binding get() = _binding!! private val binding get() = _binding!!
private val adapter: TaskListAdapter by lazy { private val adapter: TaskListAdapter by lazy {
TaskListAdapter( TaskListAdapter(
downloadManager, uploadManager downloadManager, uploadManager,binding.taskListRecyclerview
) { _, taskBean -> ) { _, status, taskBean ->
if(taskBean.hadLinkDvoList.isEmpty()){ if(taskBean.hadLinkDvoList.isEmpty()){
Toast.makeText(context, "数据错误无Link数据", Toast.LENGTH_SHORT).show() Toast.makeText(context, "数据错误无Link数据", Toast.LENGTH_SHORT).show()
} }
viewModel.setSelectTaskBean(taskBean) if(status==TaskListAdapter.Companion.ItemClickStatus.ITEM_LAYOUT_CLICK){
viewModel.setSelectTaskBean(taskBean as TaskBean)
}else if(status==TaskListAdapter.Companion.ItemClickStatus.DELETE_LAYOUT_CLICK){
context?.let { viewModel.removeTask(it, taskBean as TaskBean) }
}else if(status==TaskListAdapter.Companion.ItemClickStatus.UPLOAD_LAYOUT_CLICK){
showLoadingDialog("正在校验")
Toast.makeText(context, "正在校验", Toast.LENGTH_SHORT).show()
viewModel.checkUploadTask(binding.root.context,taskBean)
} else {
}
} }
} }
@ -64,6 +88,16 @@ class TaskListFragment : BaseFragment() {
adapter.refreshData(it) adapter.refreshData(it)
} }
//监听并调用上传
viewModel.liveDataTaskUpload.observe(viewLifecycleOwner){
for ((key, value) in it) {
if(value){
adapter.uploadTask(key)
}
}
hideLoadingDialog()
}
binding.taskListSearch.addTextChangedListener(object : TextWatcher { binding.taskListSearch.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
} }

View File

@ -1,5 +1,6 @@
package com.navinfo.omqs.ui.fragment.tasklist package com.navinfo.omqs.ui.fragment.tasklist
import android.app.Dialog
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color
import android.os.Build import android.os.Build
@ -9,6 +10,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.navinfo.collect.library.data.entity.HadLinkDvoBean import com.navinfo.collect.library.data.entity.HadLinkDvoBean
import com.navinfo.collect.library.data.entity.QsRecordBean
import com.navinfo.collect.library.data.entity.TaskBean import com.navinfo.collect.library.data.entity.TaskBean
import com.navinfo.collect.library.map.NIMapController import com.navinfo.collect.library.map.NIMapController
import com.navinfo.collect.library.utils.GeometryTools import com.navinfo.collect.library.utils.GeometryTools
@ -16,12 +18,12 @@ import com.navinfo.omqs.Constant
import com.navinfo.omqs.http.NetResult import com.navinfo.omqs.http.NetResult
import com.navinfo.omqs.http.NetworkService import com.navinfo.omqs.http.NetworkService
import com.navinfo.omqs.tools.FileManager import com.navinfo.omqs.tools.FileManager
import com.navinfo.omqs.ui.dialog.FirstDialog
import com.navinfo.omqs.util.DateTimeUtil import com.navinfo.omqs.util.DateTimeUtil
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import io.realm.Realm import io.realm.Realm
import kotlinx.coroutines.* import kotlinx.coroutines.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.max
@HiltViewModel @HiltViewModel
@ -38,6 +40,12 @@ class TaskViewModel @Inject constructor(
* 用来更新当前任务 * 用来更新当前任务
*/ */
val liveDataTaskLinks = MutableLiveData<List<HadLinkDvoBean>>() val liveDataTaskLinks = MutableLiveData<List<HadLinkDvoBean>>()
/**
* 用来更新数据是否可以上传
*/
val liveDataTaskUpload = MutableLiveData<Map<TaskBean, Boolean>>()
private val colors = private val colors =
arrayOf(Color.RED, Color.YELLOW, Color.BLUE, Color.MAGENTA, Color.GREEN, Color.CYAN) arrayOf(Color.RED, Color.YELLOW, Color.BLUE, Color.MAGENTA, Color.GREEN, Color.CYAN)
@ -76,11 +84,11 @@ class TaskViewModel @Inject constructor(
task.status = item.status task.status = item.status
task.currentSize = item.currentSize task.currentSize = item.currentSize
//已上传后不在更新操作时间 //已上传后不在更新操作时间
if(task.syncStatus!= FileManager.Companion.FileUploadStatus.DONE){ if (task.syncStatus != FileManager.Companion.FileUploadStatus.DONE) {
//赋值时间,用于查询过滤 //赋值时间,用于查询过滤
task.operationTime = DateTimeUtil.getNowDate().time task.operationTime = DateTimeUtil.getNowDate().time
} }
}else{ } else {
//赋值时间,用于查询过滤 //赋值时间,用于查询过滤
task.operationTime = DateTimeUtil.getNowDate().time task.operationTime = DateTimeUtil.getNowDate().time
} }
@ -110,10 +118,13 @@ class TaskViewModel @Inject constructor(
} }
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
//过滤掉已上传的超过90天的数据 //过滤掉已上传的超过90天的数据
var nowTime:Long = DateTimeUtil.getNowDate().time var nowTime: Long = DateTimeUtil.getNowDate().time
var beginNowTime:Long = nowTime - 90*3600*24*1000L var beginNowTime: Long = nowTime - 90 * 3600 * 24 * 1000L
var syncUpload:Int = FileManager.Companion.FileUploadStatus.DONE var syncUpload: Int = FileManager.Companion.FileUploadStatus.DONE
val objects = realm.where(TaskBean::class.java).notEqualTo("syncStatus",syncUpload).or().between("operationTime",beginNowTime,nowTime).equalTo("syncStatus",syncUpload).findAll() val objects =
realm.where(TaskBean::class.java).notEqualTo("syncStatus", syncUpload).or()
.between("operationTime", beginNowTime, nowTime)
.equalTo("syncStatus", syncUpload).findAll()
taskList = realm.copyFromRealm(objects) taskList = realm.copyFromRealm(objects)
for (item in taskList) { for (item in taskList) {
FileManager.checkOMDBFileInfo(item) FileManager.checkOMDBFileInfo(item)
@ -244,4 +255,90 @@ class TaskViewModel @Inject constructor(
liveDataTaskLinks.postValue(list) liveDataTaskLinks.postValue(list)
} }
} }
fun removeTask(context: Context, taskBean: TaskBean) {
if (taskBean != null) {
val mDialog = FirstDialog(context)
mDialog.setTitle("提示?")
mDialog.setMessage("是否关闭,请确认!")
mDialog.setPositiveButton("确定", object : FirstDialog.OnClickListener {
override fun onClick(dialog: Dialog?, which: Int) {
mDialog.dismiss()
viewModelScope.launch(Dispatchers.IO) {
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
val objects = it.where(TaskBean::class.java)
.equalTo("id", taskBean.id).findFirst()
objects?.deleteFromRealm()
}
//遍历删除对应的数据
taskBean.hadLinkDvoList.forEach { hadLinkDvoBean ->
val qsRecordList = realm.where(QsRecordBean::class.java)
.equalTo("linkId", hadLinkDvoBean.linkPid).findAll()
if (qsRecordList != null && qsRecordList.size > 0) {
val copyList = realm.copyFromRealm(qsRecordList)
copyList.forEach {
it.deleteFromRealm()
mapController.markerHandle.removeQsRecordMark(it)
mapController.mMapView.vtmMap.updateMap(true)
}
}
}
//过滤掉已上传的超过90天的数据
var nowTime: Long = DateTimeUtil.getNowDate().time
var beginNowTime: Long = nowTime - 90 * 3600 * 24 * 1000L
var syncUpload: Int = FileManager.Companion.FileUploadStatus.DONE
val objects = realm.where(TaskBean::class.java)
.notEqualTo("syncStatus", syncUpload).or()
.between("operationTime", beginNowTime, nowTime)
.equalTo("syncStatus", syncUpload).findAll()
val taskList = realm.copyFromRealm(objects)
for (item in taskList) {
FileManager.checkOMDBFileInfo(item)
}
liveDataTaskList.postValue(taskList)
}
}
})
mDialog.setNegativeButton("取消", null)
mDialog.show()
}
}
fun checkUploadTask(context: Context, taskBean: TaskBean) {
viewModelScope.launch(Dispatchers.IO) {
val realm = Realm.getDefaultInstance()
taskBean.hadLinkDvoList.forEach { hadLinkDvoBean ->
val objects = realm.where(QsRecordBean::class.java)
.equalTo("linkId", hadLinkDvoBean.linkPid).findAll()
val map: MutableMap<TaskBean, Boolean> = HashMap<TaskBean, Boolean>()
if (objects.isEmpty() && hadLinkDvoBean.reason.isEmpty()) {
withContext(Dispatchers.Main) {
liveDataTaskUpload.postValue(map)
val mDialog = FirstDialog(context)
mDialog.setTitle("提示?")
mDialog.setMessage("此任务中存在未测评link请确认")
mDialog.setPositiveButton(
"确定",
object : FirstDialog.OnClickListener {
override fun onClick(dialog: Dialog?, which: Int) {
mDialog.dismiss()
map[taskBean] = true
liveDataTaskUpload.postValue(map)
}
})
mDialog.setNegativeButton("取消", object : FirstDialog.OnClickListener {
override fun onClick(dialog: Dialog?, which: Int) {
mDialog.dismiss()
}
})
mDialog.show()
}
return@launch
}
map[taskBean] = true
liveDataTaskUpload.postValue(map)
}
}
}
} }

View File

@ -0,0 +1,291 @@
package com.navinfo.omqs.ui.widget
import android.animation.ValueAnimator
import android.animation.ValueAnimator.AnimatorUpdateListener
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.view.*
import android.widget.LinearLayout
import androidx.recyclerview.widget.RecyclerView
import com.navinfo.omqs.R
import kotlin.math.abs
/**
* Description:左滑删除按钮
*
* Time:2021/7/1-20:37
* Author:我叫PlusPlus
*/
class LeftDeleteView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
/**
* 上下文
*/
private val mContext = context
/**
* 最小触摸距离
*/
private var mMinTouchDistance : Int = 0
/**
* 右边可滑动距离
*/
private var mRightCanDistance :Int = 0
/**
* 按下时 x
*/
private var mInitX : Float = 0f
/**
* 按下y
*/
private var mInitY : Float = 0f
/**
* 属性动画
*/
private var mValueAnimator: ValueAnimator? = null
/**
* 动画时长
*/
private var mAnimDuring = 300
/**
* RecyclerView
*/
private var mRecyclerView: RecyclerView? = null
/**
* 是否重新计算
*/
private var needResetCompute = true
/**
* 状态监听
*/
var mStatusChangeLister : ((Boolean)-> Unit) ? = null
init {
//通过自定义属性获取删除按钮的宽度
val array = mContext.obtainStyledAttributes(attrs, R.styleable.LeftDeleteView)
val delWidth = array.getFloat(R.styleable.LeftDeleteView_deleteBtnWidth, 0f)
array.recycle()
mMinTouchDistance = ViewConfiguration.get(mContext).scaledTouchSlop
//将dp转成PX
val var2: Float = mContext.resources.displayMetrics.density
//计算向右可以滑动的距离单位PX
mRightCanDistance = (delWidth * var2 + 0.5f).toInt()
setBackgroundColor(Color.TRANSPARENT)
orientation = HORIZONTAL
}
/**
* 设置RecyclerView
*/
fun setRecyclerView(recyclerView: RecyclerView) {
mRecyclerView = recyclerView
}
/**
* 处理触摸事件
*/
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
val actionMasked = ev.actionMasked
when (actionMasked) {
MotionEvent.ACTION_DOWN -> {
mInitX = ev.rawX + scrollX
mInitY = ev.rawY
clearAnim()
}
MotionEvent.ACTION_MOVE -> {
if (mInitX - ev.rawX < 0) {
// mRecyclerView拦截
mRecyclerView?.let {
if (needResetCompute) {
it.requestDisallowInterceptTouchEvent(false)
needResetCompute = false
}
}
return false
}
// y轴方向上达到滑动最小距离, x 轴未达到
if (abs(ev.rawY - mInitY) >= mMinTouchDistance
&& abs(ev.rawY - mInitY) > abs(mInitX - ev.rawX - scrollX)) {
// mRecyclerView拦截
mRecyclerView?.let {
if (needResetCompute) {
it.requestDisallowInterceptTouchEvent(false)
needResetCompute = false
}
}
return false
}
// x轴方向达到了最小滑动距离y轴未达到
if (abs(mInitX - ev.rawX - scrollX) >= mMinTouchDistance
&& abs(ev.rawY - mInitY) <= abs(mInitX - ev.rawX - scrollX)) {
// mRecyclerView拦截
mRecyclerView?.let {
if (needResetCompute) {
it.requestDisallowInterceptTouchEvent(false)
needResetCompute = false
}
}
return true
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
mRecyclerView?.let {
it.requestDisallowInterceptTouchEvent(false)
needResetCompute = true
}
}
else -> {
}
}
return super.onInterceptTouchEvent(ev)
}
/**
* 处理触摸事件
* 需要注意:何时处理左滑何时不处理
*/
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(ev: MotionEvent): Boolean {
when (ev.actionMasked) {
MotionEvent.ACTION_DOWN -> {
mInitX = ev.rawX + scrollX
mInitY = ev.rawY
clearAnim()
}
MotionEvent.ACTION_MOVE -> {
if (mInitX - ev.rawX < 0) {
// 让父级容器拦截
mRecyclerView?.let {
if (needResetCompute) {
it.requestDisallowInterceptTouchEvent(false)
needResetCompute = false
}
}
}
// y轴方向上达到滑动最小距离, x 轴未达到
if (abs(ev.rawY - mInitY) >= mMinTouchDistance
&& abs(ev.rawY - mInitY) > abs(mInitX - ev.rawX - scrollX)) {
// mRecyclerView拦截
mRecyclerView?.let {
if (needResetCompute) {
it.requestDisallowInterceptTouchEvent(false)
needResetCompute = false
}
}
}
// x轴方向达到了最小滑动距离y轴未达到
if (abs(mInitX - ev.rawX - scrollX) >= mMinTouchDistance
&& abs(ev.rawY - mInitY) <= abs(mInitX - ev.rawX - scrollX)) {
// mRecyclerView拦截
mRecyclerView?.let {
if (needResetCompute) {
it.requestDisallowInterceptTouchEvent(false)
needResetCompute = false
}
}
}
//手指移动距离超过最小距离
var translationX = mInitX - ev.rawX
//滑动距离已经大于右边可伸缩的距离后, 重新设置
if (translationX > mRightCanDistance) {
mInitX = ev.rawX + mRightCanDistance
}
//互动距离小于0那么重新设置初始位置
if (translationX < 0) {
mInitX = ev.rawX
}
translationX = if (translationX > mRightCanDistance) mRightCanDistance.toFloat() else translationX
translationX = if (translationX < 0) 0f else translationX
// 向左滑动
if (translationX <= mRightCanDistance && translationX >= 0) {
scrollTo(translationX.toInt(), 0)
return true
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
mRecyclerView?.let {
it.requestDisallowInterceptTouchEvent(false)
needResetCompute = true
}
upFingerAnim()
return true
}
else -> {
}
}
return true
}
/**
* 清理动画
*/
private fun clearAnim() {
mValueAnimator?.let {
it.end()
it.cancel()
mValueAnimator = null
}
}
/**
* 手指抬起开始执行动画
*/
private fun upFingerAnim() {
val scrollX = scrollX
if (scrollX == mRightCanDistance || scrollX == 0) {
//回调显示状态
mStatusChangeLister?.invoke(scrollX == mRightCanDistance)
return
}
clearAnim()
// 如果显出一半松开手指,那么自动完全显示。否则完全隐藏
if (scrollX >= mRightCanDistance / 2) {
mValueAnimator = ValueAnimator.ofInt(scrollX, mRightCanDistance)
//进行滑动
mValueAnimator?.addUpdateListener { animation ->
val value = animation.animatedValue as Int
scrollTo(value, 0)
}
mValueAnimator?.duration = mAnimDuring.toLong()
mValueAnimator?.start()
//回调显示的状态
mStatusChangeLister?.invoke(true)
} else {
mValueAnimator = ValueAnimator.ofInt(scrollX, 0)
//进行滑动
mValueAnimator?.addUpdateListener { animation ->
val value = animation.animatedValue as Int
scrollTo(value, 0)
}
mValueAnimator?.duration = mAnimDuring.toLong()
mValueAnimator?.start()
//回调关闭的状态
mStatusChangeLister?.invoke(false)
}
}
/**
* 重置按钮删除状态
*/
fun resetDeleteStatus() {
val scrollX = scrollX
if (scrollX == 0) {
return
}
clearAnim()
mValueAnimator = ValueAnimator.ofInt(scrollX, 0)
//进行滑动
mValueAnimator?.addUpdateListener(AnimatorUpdateListener { animation ->
val value = animation.animatedValue as Int
scrollTo(value, 0)
})
mValueAnimator?.duration = mAnimDuring.toLong()
mValueAnimator?.start()
//回调关闭的状态
mStatusChangeLister?.invoke(false)
}
}

View File

@ -1,107 +1,135 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <com.navinfo.omqs.ui.widget.LeftDeleteView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_adapter_item_select_bg" android:background="@drawable/selector_adapter_item_select_bg"
android:paddingLeft="8dp" tools:context="com.navinfo.omqs.ui.fragment.tasklist.TaskListAdapter"
android:paddingTop="6dp" app:deleteBtnWidth="64"
android:paddingRight="8dp" android:layout_height="wrap_content"
android:paddingBottom="8dp" android:layout_width="match_parent">
tools:context="com.navinfo.omqs.ui.fragment.tasklist.TaskListAdapter">
<ImageView <RelativeLayout
android:id="@+id/task_list_head" android:id="@+id/task_item_layout"
android:layout_width="16dp" android:paddingLeft="8dp"
android:layout_height="16dp" android:paddingTop="6dp"
android:layout_alignTop="@id/task_name" android:paddingRight="8dp"
android:layout_marginLeft="6dp" android:paddingBottom="8dp"
android:layout_marginTop="2dp"
android:layout_marginRight="6dp"
android:background="@drawable/selector_task_head" />
<TextView
android:id="@+id/task_name"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent">
android:layout_toRightOf="@id/task_list_head"
android:text="任务名称" <ImageView
android:textColor="#15141F" android:id="@+id/task_list_head"
android:textSize="14sp" /> android:layout_width="16dp"
android:layout_height="16dp"
android:layout_alignTop="@id/task_name"
android:layout_marginLeft="6dp"
android:layout_marginTop="2dp"
android:layout_marginRight="6dp"
android:background="@drawable/selector_task_head" />
<TextView
android:id="@+id/task_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/task_list_head"
android:text="任务名称"
android:textColor="#15141F"
android:textSize="14sp" />
<TextView <TextView
android:id="@+id/task_data_version" android:id="@+id/task_data_version"
style="@style/map_size_font_style" style="@style/map_size_font_style"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/task_name" android:layout_below="@id/task_name"
android:layout_alignLeft="@id/task_name" android:layout_alignLeft="@id/task_name"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
android:layout_marginBottom="5dp" android:layout_marginBottom="5dp"
android:text="版本号" android:text="版本号"
android:textColor="@color/gray_121" android:textColor="@color/gray_121"
android:textSize="13sp" /> android:textSize="13sp" />
<TextView <TextView
android:id="@+id/task_city_name" android:id="@+id/task_city_name"
style="@style/map_size_font_style" style="@style/map_size_font_style"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/task_data_version" android:layout_below="@id/task_data_version"
android:layout_alignLeft="@id/task_name" android:layout_alignLeft="@id/task_name"
android:text="省市名称" android:text="省市名称"
android:textColor="@color/gray_121" android:textColor="@color/gray_121"
android:textSize="13sp" /> android:textSize="13sp" />
<com.navinfo.omqs.ui.widget.TextProgressButtonBar <com.navinfo.omqs.ui.widget.TextProgressButtonBar
android:id="@+id/task_download_btn" android:id="@+id/task_download_btn"
android:layout_width="75dp" android:layout_width="75dp"
android:layout_height="22dp" android:layout_height="22dp"
android:layout_alignBottom="@id/task_city_name" android:layout_alignBottom="@id/task_city_name"
android:layout_alignParentRight="true" android:layout_alignParentRight="true"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
app:backgroundcolor="#888FB3" app:backgroundcolor="#888FB3"
app:text="下载" app:text="下载"
app:textSize="@dimen/card_title_font_2size" app:textSize="@dimen/card_title_font_2size"
app:textcolor="@color/white" /> app:textcolor="@color/white" />
<com.navinfo.omqs.ui.widget.TextProgressButtonBar <com.navinfo.omqs.ui.widget.TextProgressButtonBar
android:id="@+id/task_upload_btn" android:id="@+id/task_upload_btn"
android:layout_width="75dp" android:layout_width="75dp"
android:layout_height="22dp" android:layout_height="22dp"
android:layout_alignBottom="@id/task_city_name" android:layout_alignBottom="@id/task_city_name"
android:layout_alignParentRight="true" android:layout_alignParentRight="true"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
android:visibility="gone" android:visibility="gone"
app:backgroundcolor="#888FB3" app:backgroundcolor="#888FB3"
app:text="未上传" app:text="未上传"
app:textSize="@dimen/card_title_font_2size" app:textSize="@dimen/card_title_font_2size"
app:textcolor="@color/white" /> app:textcolor="@color/white" />
<TextView <TextView
android:id="@+id/task_status" android:id="@+id/task_status"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:layout_toLeftOf="@id/task_download_btn" android:layout_toLeftOf="@id/task_download_btn"
android:clickable="true" android:clickable="true"
android:focusable="false" android:focusable="false"
android:shadowColor="@android:color/transparent" android:shadowColor="@android:color/transparent"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="@dimen/card_title_font_2size" /> android:textSize="@dimen/card_title_font_2size" />
<TextView
android:id="@+id/task_progress_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/task_download_btn"
android:layout_alignBottom="@id/task_download_btn"
android:layout_toLeftOf="@id/task_download_btn"
android:gravity="center"
android:visibility="invisible" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/task_delete_layout"
android:background="@color/red"
android:layout_width="64dp"
android:layout_height="match_parent">
<TextView
android:layout_centerVertical="true"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:enabled="false"
android:text="关闭"
android:textColor="#15141F"
android:textSize="@dimen/left_pannel_title_font" />
</RelativeLayout>
</com.navinfo.omqs.ui.widget.LeftDeleteView>
<TextView
android:id="@+id/task_progress_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/task_download_btn"
android:layout_alignBottom="@id/task_download_btn"
android:layout_toLeftOf="@id/task_download_btn"
android:gravity="center"
android:visibility="invisible" />
</RelativeLayout>

View File

@ -31,8 +31,7 @@
android:paddingRight="@dimen/eight" android:paddingRight="@dimen/eight"
android:paddingTop="@dimen/eight" android:paddingTop="@dimen/eight"
android:text="title" android:text="title"
android:textColor="@color/black" android:textColor="@color/black" />
android:textSize="@dimen/card_title_font_2size" />
<View <View
android:id="@+id/title_divider" android:id="@+id/title_divider"
@ -82,7 +81,7 @@
android:paddingTop="@dimen/twenty" android:paddingTop="@dimen/twenty"
android:text="提示内容" android:text="提示内容"
android:textColor="@color/black" android:textColor="@color/black"
android:textSize="@dimen/card_title_font_3size" /> android:textSize="@dimen/card_title_font_2size" />
</RelativeLayout> </RelativeLayout>

View File

@ -9,4 +9,10 @@
<attr name="textSize" format="dimension" /> <attr name="textSize" format="dimension" />
<attr name="text" format="string" /> <attr name="text" format="string" />
</declare-styleable> </declare-styleable>
//自定义删除按钮的宽度
<declare-styleable name="LeftDeleteView">
<attr name="deleteBtnWidth" format="float"/>
</declare-styleable>
</resources> </resources>

View File

@ -74,5 +74,4 @@ open class TaskBean @JvmOverloads constructor(
fun getDownLoadUrl(): String { fun getDownLoadUrl(): String {
return "${Constant.SERVER_ADDRESS}devcp/downFile?fileStr=$id" return "${Constant.SERVER_ADDRESS}devcp/downFile?fileStr=$id"
} }
} }