欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android Kotlin开发问卷调查编辑器

程序员文章站 2022-05-05 18:24:53
...

关于这个作者

作为一个初学者但是没有女朋友的大学生,所以前所未有的荷尔蒙全投入到代码中,花了5个月学了java开发了springmvc后端,哎不够啊!!我要当全栈大王!但还是止不住我的笨,

因此看在我每天百分之四十的时间都在敲代码的份上,请大家给点支持,有错误欢迎指出。

 

关于这个项目

语言:Kotlin

环境:Java1.8

IDE:Android Studio

 

实现问卷调查编辑器,使用了RecyclerView库,实现了动态控件的添加,数据的绑定。

 

编辑器有三个按钮,增加陈述题,单选题,多选题,后面两种题型可以增加多个选项,并且这些都会有删除功能。

Android Kotlin开发问卷调查编辑器


代码在github里面,如果对大家有帮助,请给个星支持一下呀!!

https://github.com/rendawudi/AndroidRecyclerQuestionnaireMkr


具体代码我就不展示了,我就总结一下我踩的RecyclerView中的巨坑吧(这些坑肯定是因为我经验不够才这样的。。。。)

 

首先是动态加载控件,我一开始是在Adapter中的onBindViewHolder根据 + 控件监听动态addview实现选项的增加,如图



果呢

不要忘了ViewHolder的复用功能啊!!每次从数据源list中读取item的时候都会执行onBindViewHolder,而这个方法会从缓存中读取之前已存在的view进行匹配加载
而我每次都addview后,就会出现每次点击 多选题 这个按钮时,他会加载一个已经加载了一堆选项的题目



因此,我上网查如何禁止复用,holder.setIsRecyclable(false) 简直是我梦中情人
然而呢?????我居然每次点击删除后,程序通过notifyItemChanged(position)刷新时,居然画面有之前选项残留!!!漂浮并固定在屏幕上,点一下还要崩溃!!!!!
好吧 经过许多个小时的尝试,我知道了,布局的加载必须在onCreateViewHolder中进行,因此,我想出个办法,在viewholder中增加选项布局的list


class ViewHolder : RecyclerView.ViewHolder {

        var selectionNum = 0
        var selectionEdit: ArrayList<EditText>
        var selectionButton: ArrayList<Button>
        .....
}

并且在onCreateViewHolder中创建view时,根据数据源每个问题的选项的个数的数量加载 选项布局

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        var view: View = LayoutInflater.from(parent.context).inflate(R.layout.question, parent, false)
        var selectionEdit: ArrayList<EditText> = ArrayList()
        var selectionButton: ArrayList<Button> = ArrayList()
        for (i in 0..viewType - 1) {
            var linLayout: LinearLayout = view.findViewById(R.id.danxuanLayout) as LinearLayout
            val itemLayout: LayoutInflater = LayoutInflater.from(view.context)
            var selectionLayout: LinearLayout = itemLayout.inflate(R.layout.selection, null).findViewById(R.id.selectionLayout) as LinearLayout
            linLayout.addView(selectionLayout)
            selectionEdit.add(selectionLayout.findViewById(R.id.editSelection) as EditText)
            selectionButton.add(selectionLayout.findViewById(R.id.delSelection) as Button)
        }
        var holder: ViewHolder = ViewHolder(view, selectionEdit, selectionButton)
        return holder
    }


OK!大功告成

接下来一个坑

holder.wendatiButton.setOnClickListener {
                    if (holder.delBok) {
                        holder.delBok = false
                        mQstList.removeAt(position)
                        notifyItemRemoved(position)
                        notifyItemChanged(position, itemCount)
                        Thread(Runnable {
                            Thread.sleep(200)
                            holder.delBok = true
                        }).start()
                    }
                }

删除啊,RecyclerView删除一个item时,会执行一个动画诶!它会慢慢的消失,然而最坑的是什么,它慢就算了,居然还可以点击!!!我去
点一下就崩溃,提示数组越界
所以看上面,我加了个删除判断标志,让他在动画播放时,无法点击删除,然后慢慢点没问题了!!!怎么快速点击呢?网上有个土方法,加个线程,在这个线程结束后也就是动画结束后
就可以点击删除了
 
然后呢??
什么坑都难不倒我嘛???
看图


怎么我往下翻一下再回一下头,“yyyy”数据就没了啊
我本以为是数据源没有绑定成功,结果查了资料不存在的
原来是EditText按钮监听有毒啊!
我最开始设置EditText是通过TextWatcher 中afterTextChanged,
然而并没有卵用,为啥?
因为只要一删除选项或者问题,这个afterTextChanged就会执行一下,我数据源都没这东西了,它一执行,就崩溃了。。。。。
因此,我要选一个不管出了啥事,监听器只看软键盘或者光标的脸色行事
 
 
于是,我开始选了setOnEditorActionListener 中的onEditorAction,判断用户按了一下回车键,不对啊!
我要是用户的话,我要是突然想起有什么东西错了要用手点一下其他选项,没有按回车,那岂不是数据就没了???
不要不要!!
的,我又选了setOnFocusChangeListener没错,就是她!!!我的天,真是适合我,只要焦点一改变,就把数据读取到数据源中
哇哦!!!
还是有个小bug
那就是你想想,用户写完后,他没有点其他的EditText,他直接点击了保存!那就相当于焦点没有改变啊,就意味着你最后一个选项的数据没有保存啊
怎么办??
“聪明的我”将保存按钮设置成了
android:focusable="true"
android:focusableInTouchMode="true"
哈哈哈哈哈哈
结果变成了点两下才能保存。。。。。
为啥
因为这是焦点模式开启,就像windows系统中的,鼠标点一下是选中,点两下是执行
哦!我的天,用户体验极差,但是这难不倒聪明的我
R.id.jiancha ->{
    v.isFocusable = true
    v.isFocusableInTouchMode = true
    v.requestFocus()
    var gson: Gson = Gson()
    Log.d("值为",gson.toJson(taskList))
    v.isFocusable = false
    v.isFocusableInTouchMode = false
}

我将保存按钮点击事件中,设置了开启焦点模式,并将其设置为焦点,POFET,数据全部都保存啦!!!!!!!!!!!!!!!!!
 
还有其他的notifyItemChanged闪烁啊,什么焦点监听不响应啊之类的,网上百度都有,而我说的这些,大部分网上都没有。。。