前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >EditText在RecyclerView中的解决方案

EditText在RecyclerView中的解决方案

作者头像
用户1108631
发布2019-08-14 18:02:10
2.6K0
发布2019-08-14 18:02:10
举报

有时候,一个列表中的Item会有EditText的出现,而由于View复用机制,如果不好好处理EditText,将会出现一些问题。之前做项目中也遇到了这个问题,通过摸索以及思考,最终得到了解决方案。

其实有些问题的出现,还是由于没有理解RecyclerView的复用机制和EditText,主要原因还是菜,哈哈。

菜是原罪

EditText在RecyclerView中的问题

例子是这样的,每个Item包含一个title、一张图片以及一个评分,这个评分就是通过输入框来输入的。

问题1——复用机制、未绑定数据导致的

先看下第一段Adapter里面的逻辑:

代码语言:javascript
复制
class PicViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

    var ivPic: ImageView = itemView.findViewById(R.id.ivPic)
    var etScore: EditText = itemView.findViewById(R.id.etScore)
    var tvTitle: TextView = itemView.findViewById(R.id.tvTitle)

    fun updateView(picItem: PicItem) {
        ivPic.setImageResource(picItem.picResId)
        tvTitle.text = picItem.title
        if (picItem.score == null) etScore.hint = "请输入分数" else etScore.setText(picItem.score)
    }
}

上面是ViewHolder的代码,Adapter的onBindViewHolder就是调用了updateView()方法,这里面暂时还没把输入框的内容和PicItem绑定。先看下效果如下:

这里,每张图片输入图片title对应的分数,可以看到,由于未绑定数据和RecyclerView的复用机制的存在,在一些图片中还没输入分数,就已经出现分数了。那下面先来进行数据的绑定。

问题2——错误的绑定机制

要想在EditText输入后绑定数据,怎么搞?TextWatcher了解一下,操作方式如下:

代码语言:javascript
复制
class PicViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

    var ivPic: ImageView = itemView.findViewById(R.id.ivPic)
    var etScore: EditText = itemView.findViewById(R.id.etScore)
    var tvTitle: TextView = itemView.findViewById(R.id.tvTitle)
    var myTextWatcher: MyTextWatcher=MyTextWatcher()

    fun updateView(picItem: PicItem) {
        ivPic.setImageResource(picItem.picResId)
        tvTitle.text = picItem.title
        if (picItem.score == null) etScore.hint = "请输入分数" else etScore.setText(picItem.score)
        myTextWatcher.picItem=picItem
        etScore.addTextChangedListener(myTextWatcher)
    }
}

class MyTextWatcher: TextWatcher {

    lateinit var picItem:PicItem

    override fun afterTextChanged(s: Editable?) {
        picItem?.apply {
            score=s?.toString()
        }
    }

    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
    }

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
    }
}

效果如下:

可以发现,还是乱的。想了想,这是咋回事呢?原来是因为这里是addTextWatcher,而不是setTextWatcher,也就是在复用的时候,同一个EditText添加了多个TextWatcher,怪不得分数9还能出现在上面了。

想清了原因,那就好办了。 首先我是试了一个,removeTextWatcher的方法,那就是在Adapter的detachViewHolderFromWindow方法中移除TextWatcher,如下:

代码语言:javascript
复制
class PicAdapter(val picItems: List<PicItem>) : RecyclerView.Adapter<PicViewHolder>() {
    override fun onViewDetachedFromWindow(holder: PicViewHolder) {
        super.onViewDetachedFromWindow(holder)
        holder.etScore.removeTextChangedListener(holder.myTextWatcher)
    }
}

实践发现,依赖onViewDetachedFromWindow是不靠谱的。

解决方案

经过思考,由于RecyclerView的复用机制,导致了以下关系的存在:

一个ViewHolder——>一个EditText——>多个TextWatcher——>多个PicItem

这里我们可以将多个TextWatcher始终绑定一个,那就需要在ViewHolder的初始化里面操作,而不是在updateView,因为会多次bind,这就得到了以下关系:

一个ViewHolder——>一个EditText——>一个TextWatcher——>多个PicItem

那么也就是说TextWatcher负责多个PicItem的更新,怎么做呢?

很简单,在updateView(),也就是bind过程中每次去更新PicItem就可以了。最终代码如下:

代码语言:javascript
复制
class PicViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

    var ivPic: ImageView = itemView.findViewById(R.id.ivPic)
    var etScore: EditText = itemView.findViewById(R.id.etScore)
    var tvTitle: TextView = itemView.findViewById(R.id.tvTitle)
    var myTextWatcher: MyTextWatcher = MyTextWatcher()

    init {
        etScore.addTextChangedListener(myTextWatcher)
    }

    fun updateView(picItem: PicItem) {
        myTextWatcher.picItem = picItem
        ivPic.setImageResource(picItem.picResId)
        tvTitle.text = picItem.title
        if (picItem.score == null) {
            etScore.hint = "请输入分数"
            etScore.setText("")
        } else {
            etScore.setText(picItem.score)
        }
    }
}

最终效果如下:

模拟器滑动起来感觉有点便秘,将就看着吧。。。。

另外如果对这个美女感兴趣,她叫刘芸,不要谢我,去百度搜图片去吧。。。???

总结

其实后来想想,如果能明白RecyclerView复用机制,EditText的TextWatcher机制,其实很容易解决这种问题,那么绕路了的原因就是因为。哎,不多说了,学习去了。。

代码地址:https://github.com/wangli135/ClimbDemo/tree/master/app

公众号只支持2m以下的gif,很蛋疼,就搞成视频了,可以到原文链接看gif。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-01-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 每天学点Android知识 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • EditText在RecyclerView中的问题
    • 问题1——复用机制、未绑定数据导致的
      • 问题2——错误的绑定机制
      • 解决方案
      • 总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档