android - 如何在 RecyclerView 中处理链接到特定卡片的视图持有者?
问题描述
我正在开发一个 android 项目,在该项目中,我想通过向右或向左滑动项目来从垂直回收器视图中删除项目。就删除项目而言,我能够正确地做到这一点。删除项目并致电后出现问题notifyDataSetChanged().
现在在刷新项目时,适配器使用以前的视图持有者来显示卡片。但是在删除一个项目时,我将它的一些布局向左和向右移动。因此,当新项目占据同一个视图持有者时,所有的翻译都会被保留,因此会在屏幕边界之外创建新项目的一些视图(因为我在删除占据该位置的前一个项目时移动了该视图持有者)。
所以我的问题是(以下任何一项的解决方案都将解决我面临的问题),
- Java中是否有像c++这样的“免费”功能?这样我就可以释放那个视图持有者。
- 如何确保回收站视图不会重用特定的视图持有者?
- 如何在所有动画完成之前将布局重置为原始状态?这样我就可以重置所有翻译
谢谢你。
编辑:
下面是适配器和视图支架的代码,如果有人想看看的话。由于视图持有者太大而无法直接理解,所以这里是其中使用的功能的总结:
- init -> 只在点击监听器上设置。
- updateUI -> 设置更多侦听器并设置卡片中的文本和其他字段。
- 当 MotionEvent.ACTION_DOWN 时调用 pressDown ->。
- 当 MotionEvent.ACTION_UP 时调用 pressUP ->。
- animateViewDisappear -> 动画监听器。
- 归档 -> 删除一个元素并告诉适配器数据发生了变化。
- pressMove -> 在单击按钮后发生运动时感知。
- toggleShowHideView -> 更改某些视图的可见性。
- closeOpenedLayout -> 关闭一些展开的布局。
适配器:
class LocalAdapter(var localCardsInfo : ArrayList<LocalModel>?,var fragment: LocalListingFragment) : RecyclerView.Adapter<LocalHolder>() {
fun refreshDataOnOrientationChange(mLocalCards : ArrayList<LocalModel>?){
if (localCardsInfo!!.size>0)
localCardsInfo!!.clear()
localCardsInfo = mLocalCards
notifyDataSetChanged()
}
override fun getItemCount(): Int {
return localCardsInfo!!.size
}
override fun onBindViewHolder(holder: LocalHolder, position: Int) {
if (localCardsInfo!=null)
holder.updateUI(position,localCardsInfo!![position])
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LocalHolder {
val card_a : View = LayoutInflater.from(parent.context).inflate(R.layout.card_local_a,parent,false)
return LocalHolder(card_a,fragment)
}
}
视图持有人:
class LocalHolder(itemView : View,val fragment: LocalListingFragment) : RecyclerView.ViewHolder(itemView),OpenedLayoutManagerLocal{
private val TAG = "iotcontrollerapp.@Debug"
private var _xDelta: Float = 0f
private var originalDelta : Float = 0f
private var directionOut1 = false
private var directionOut = false
private var previousX = 0f
var isFavourite : Boolean = false
var isPropertyPanelOpen : Boolean = false
val deviceName : TextView = itemView.findViewById(R.id.deviceNameLocal)
val deviceRoom : TextView = itemView.findViewById(R.id.deviceRoomLocal)
val deviceOnOff : TextView = itemView.findViewById(R.id.deviceOnOffLocal)
val showHideLayout : LinearLayout = itemView.findViewById(R.id.showHideLayoutLocal)
val showHideProperties : TextView = itemView.findViewById(R.id.showHidePropertiesLocal)
val showHideButton : ImageView = itemView.findViewById(R.id.showHideButtonLocal)
val favouriteButton : ImageButton = itemView.findViewById(R.id.imageFavouriteButtonLocal)
val moveButton : MoveableViewImageButton = itemView.findViewById(R.id.imageMoveButtonLocal)
val changeFragmentToDetail : Button = itemView.findViewById(R.id.changePropertiesLocal)
val layoutForProperties : LinearLayout = itemView.findViewById(R.id.layoutForPropertyLocal)
val baseForProperties : LinearLayout = itemView.findViewById(R.id.baseForPropertyLocal)
private var model : LocalModel? = null
init {
itemView.elevation = 0f
showHideLayout.setOnClickListener({
isPropertyPanelOpen = !isPropertyPanelOpen
if (isPropertyPanelOpen){
if (openedLayoutManagerLocal != this)
openedLayoutManagerLocal?.closeOpenedLayout()
openedLayoutManagerLocal = this
showHideProperties.text = fragment.getString(R.string.close_property_panel)
showHideButton.setImageResource(R.drawable.animated_more_button_local)
}
else{
showHideProperties.text = fragment.getString(R.string.open_property_panel)
showHideButton.setImageResource(R.drawable.animated_more_button_reverse_local)
}
val mDrawable = showHideButton.drawable
if (mDrawable is Animatable)
{
(mDrawable as Animatable).start()
}
toggleShowHideView()
})
}
fun changeFavouriteButtonState(localModel: LocalModel){
isFavourite = !isFavourite
if (isFavourite){
favouriteButton.setImageResource(R.drawable.avd_heart_fill)
val a = favouriteButton.drawable
if(a is Animatable){
a.start()
}
ALL_STATIC_CONSTANTS_AND_METHODS.saveIsFavourite(fragment.activity as Context,localModel.roomName.trim() + "$" + localModel.deviceName,true)
}
else{
favouriteButton.setImageResource(R.drawable.avd_heart_break)
val a = favouriteButton.drawable
if(a is Animatable){
a.start()
}
ALL_STATIC_CONSTANTS_AND_METHODS.saveIsFavourite(fragment.activity as Context,localModel.roomName.trim() + "$" + localModel.deviceName,false)
}
}
fun updateUI(position : Int , localModel: LocalModel){
itemView.elevateLayoutLocal.visibility = View.VISIBLE
itemView.archiveLayout.visibility = View.VISIBLE
model = localModel
originalDelta = itemView.elevateLayoutLocal.x
changeFragmentToDetail.setOnClickListener({
fragment.handlerForDetail.sendEmptyMessage(position)
})
favouriteButton.setOnClickListener({
changeFavouriteButtonState(localModel)
})
moveButton.setOnTouchListener({v: View?, event: MotionEvent? ->
if (v == null || event == null) return@setOnTouchListener true
when (event.action){
MotionEvent.ACTION_UP -> {
v.performClick()
pressUP(v,event)
}
MotionEvent.ACTION_DOWN -> {
pressDown(v,event)
}
MotionEvent.ACTION_MOVE -> {
pressMove(v,event)
}
else -> {
Log.e(TAG,"Something happened")
}
}
return@setOnTouchListener true
})
isFavourite = (ALL_STATIC_CONSTANTS_AND_METHODS.getIsFavourite(fragment.activity as Context,localModel.roomName.trim() + "$" + localModel.deviceName) ?: false)
favouriteButton.setImageResource(if (isFavourite) R.drawable.vd_trimclip_heart_full else R.drawable.vd_trimclip_heart_empty)
deviceRoom.text = localModel.roomName.split("_").dropLast(1).toTypedArray().joinToString(" ")
deviceName.text = localModel.deviceName.split("_").dropLast(1).toTypedArray().joinToString(" ")
deviceOnOff.text = if (localModel.isON) fragment.getString(R.string.device_on_off_on) else fragment.getString(R.string.device_on_off_off)
val components = localModel.componentName.split(" ")
val value = localModel.value.split(" ")
val maxValue = localModel.maxValue.split(" ")
val minValue = localModel.minValue.split(" ")
if (layoutForProperties.childCount > 0)
layoutForProperties.removeAllViews()
if (components.size == value.size && minValue.size == maxValue.size && components.size == minValue.size){
for (i in 0 until components.size){
val layout : LinearLayout = LinearLayout.inflate(fragment.activity , R.layout.card_local_b , null) as LinearLayout
layout.findViewById<TextView>(R.id.propertyLocal).text = components[i].replace("_"," ")
layout.findViewById<TextView>(R.id.valueLocal).text = value[i]
layout.findViewById<TextView>(R.id.rangeLocal).text = minValue[i] + " to " + maxValue[i]
layoutForProperties.addView(layout)
}
}
}
private fun pressDown(imageButton: View, event: MotionEvent){
fragment.mLayoutManager?.setScrollEnabled(false)
openedLayoutManagerLocal?.closeOpenedLayout()
_xDelta = itemView.elevateLayoutLocal.x - event.rawX
}
private fun pressUP(imageButton: View, event: MotionEvent){
Log.e(TAG,"itemView.elevateLayoutLocal.x :: ${(itemView.elevateLayoutLocal.width / 3.toFloat()) - itemView.elevateLayoutLocal.x}")
val status = (itemView.elevateLayoutLocal.width / 3.toFloat()) < itemView.elevateLayoutLocal.x
val status1 = (itemView.elevateLayoutLocal.width / 2.toFloat()) < itemView.elevateLayoutLocal.x
itemView.elevateLayoutLocal.animate()
.x(if ((directionOut && status) || (status1 && directionOut1)) itemView.elevateLayoutLocal.width.toFloat() else originalDelta)
.setDuration(100)
.setListener(object : Animator.AnimatorListener{
override fun onAnimationCancel(animation: Animator?) {
if ((directionOut && status) || (status1 && directionOut1)) {
itemView.elevateLayoutLocal.visibility = View.GONE
val anim = ValueAnimator.ofInt(itemView.archiveLayout.measuredHeight, 0)
anim.addUpdateListener { valueAnimator ->
val `val` = valueAnimator.animatedValue as Int
val layoutParams = itemView.archiveLayout.layoutParams
layoutParams.height = `val`
itemView.archiveLayout.layoutParams = layoutParams
}
anim.addListener(animateViewDisappear(this@LocalHolder))
anim.duration = 1000
anim.start()
}else{
fragment.mLayoutManager?.setScrollEnabled(true)
}
}
override fun onAnimationEnd(animation: Animator?) {
if ((directionOut && status) || (status1 && directionOut1)) {
itemView.elevateLayoutLocal.visibility = View.GONE
val anim = ValueAnimator.ofInt(itemView.archiveLayout.measuredHeight, 0)
anim.addUpdateListener { valueAnimator ->
val `val` = valueAnimator.animatedValue as Int
val layoutParams = itemView.archiveLayout.layoutParams
layoutParams.height = `val`
itemView.archiveLayout.layoutParams = layoutParams
}
anim.addListener(animateViewDisappear(this@LocalHolder))
anim.duration = 1000
anim.start()
}else{
fragment.mLayoutManager?.setScrollEnabled(true)
}
}
override fun onAnimationRepeat(animation: Animator?) {
}
override fun onAnimationStart(animation: Animator?) {
}
}).start()
}
class animateViewDisappear(var i : LocalHolder) :Animator.AnimatorListener {
override fun onAnimationCancel(animation: Animator?) {
i.itemView.archiveLayout.visibility = View.GONE
i.itemView.elevateLayoutLocal.visibility = View.GONE
i.itemView.elevateLayoutLocal.x = i.originalDelta
val layoutParams = i.itemView.archiveLayout.layoutParams
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
i.itemView.archiveLayout.layoutParams = layoutParams
i.archived()
}
override fun onAnimationEnd(animation: Animator?) {
i.itemView.archiveLayout.visibility = View.GONE
i.itemView.elevateLayoutLocal.visibility = View.GONE
i.itemView.elevateLayoutLocal.x = i.originalDelta
val layoutParams = i.itemView.archiveLayout.layoutParams
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
i.itemView.archiveLayout.layoutParams = layoutParams
i.archived()
}
override fun onAnimationRepeat(animation: Animator?) {
}
override fun onAnimationStart(animation: Animator?) {
}
}
private fun archived(){
fragment.mLayoutManager?.setScrollEnabled(true)
if (model != null) {
ALL_STATIC_CONSTANTS_AND_METHODS.addToArchive(fragment.activity!!, model!!.roomName, model!!.deviceName)
fragment.mAdapter?.refreshDataOnOrientationChange(LocalDataService.ourInstance.getNonArchivedItems(fragment.activity!!))
}
}
private fun pressMove(imageButton: View, event: MotionEvent){
directionOut1 = itemView.elevateLayoutLocal.x >= (previousX)
directionOut = itemView.elevateLayoutLocal.x >= (previousX + 20)
previousX = itemView.elevateLayoutLocal.x
fragment.mLayoutManager?.setScrollEnabled(false)
itemView.elevateLayoutLocal.animate()
.x(event.rawX + _xDelta)
.setDuration(0)
.start()
}
fun toggleShowHideView(){
changeFragmentToDetail.visibility = if (isPropertyPanelOpen) View.VISIBLE else View.GONE
layoutForProperties.visibility = if (isPropertyPanelOpen) View.VISIBLE else View.GONE
baseForProperties.visibility = if (isPropertyPanelOpen) View.VISIBLE else View.GONE
}
override fun closeOpenedLayout() {
if (isPropertyPanelOpen){
isPropertyPanelOpen = !isPropertyPanelOpen
showHideProperties.text = fragment.getString(R.string.open_property_panel)
showHideButton.setImageResource(R.drawable.animated_more_button_reverse_local)
val mDrawable = showHideButton.drawable
if (mDrawable is Animatable)
{
(mDrawable as Animatable).start()
}
toggleShowHideView()
}
}
companion object {
var openedLayoutManagerLocal : OpenedLayoutManagerLocal? = null
}
}
解决方案
推荐阅读
- python - 从 defaultdict 打印值
- authentication - Web-Shiro getSuccessUrl 的 PassThruAuthenticationFilter
- powershell - 参数 interups docker build
- powershell - 获取 Windows 的集群详细信息
- apache - 服务 httpd restart 不显示任何信息
- c# - 在 C# 中使用内部联接语句将 nvarchar 值转换为数据类型 int 时转换失败
- selenium - 如何在 selenium 网格节点中打开本地计算机中可用的 html 文件
- c# - 将表达式谓词的左侧转换为字符串
- java - 覆盖 URLConnection 的 getInputStream 以通过自定义协议接收数据
- python - 如何将 R 的 .rdata 文件加载到 Python 中?