Android kotlin 实现仿微信快手点击列表item后弹出输入框,所item自动滚动到输入框上方功能

文章目录

  • 一、实现效果
  • 二、引入依赖
  • 三、源码实现
    • 适配器
    • 手机软键盘工具类
    • 1、列表(仿微信)
    • 2、从底部弹出列表对话框(仿快手)

一、实现效果

二、引入依赖

appbuild.gradle在添加以下代码
1、implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.6',这个里面带的适配器,直接调用就即可

BaseRecyclerViewAdapterHelper简称BRVAH

Android SDK 是否支持BaseRecyclerViewAdapterHelper:3.0.6
android compileSdkVersion 29
android compileSdkVersion 30
android compileSdkVersion 31
android compileSdkVersion 32
android compileSdkVersion 33

这依赖包还需要得到要添加,在Projectbuild.gradle在添加以下代码,不添加就不行

allprojects {
    repositories {
        ...
        maven { url "https://jitpack.io" }//加上
    }
}

2、AnyLayer:implementation "com.github.goweii:AnyLayer:4.1.4-androidx"

三、源码实现

适配器

RvAdapter.kt

package com.example.myapplication3.adapter

import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.example.myapplication3.R
import kotlinx.android.synthetic.main.rv_item.view.*

class RvAdapter(layoutResId: Int = R.layout.rv_item) :
    BaseQuickAdapter<String, BaseViewHolder>(layoutResId) {
    override fun convert(holder: BaseViewHolder, item: String) {
        holder.itemView.run {
            tv_content.text = item
        }
    }
}

布局rv_item.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/swipe_menu_layout"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="@drawable/item_bg"
    android:gravity="center">

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="菜单" />
LinearLayout>

item样式item_bg.xml


<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape android:shape="rectangle">
            <stroke android:width="1.0px" android:color="@color/line" />

            <gradient android:angle="270.0" android:endColor="#ffe8ecef" android:startColor="#ffe8ecef" />
        shape>
    item>

    <item android:state_focused="true">
        <shape android:shape="rectangle">
            <gradient android:angle="270.0" android:endColor="#ffe8ecef" android:startColor="#ffe8ecef" />

            <stroke android:width="1.0px" android:color="@color/line" />
        shape>
    item>

    <item>
        <shape android:shape="rectangle">
            <gradient android:angle="270.0" android:endColor="#ffffffff" android:startColor="#ffffffff" />

            <stroke android:width="1.0px" android:color="@color/line" />
        shape>
    item>

selector>

手机软键盘工具类

手机软键盘工具类KeyboardUtil.kt

package com.example.myapplication3.util

import android.app.Activity
import android.content.Context
import android.graphics.Rect
import android.view.View
import android.view.ViewTreeObserver.OnGlobalLayoutListener
import android.view.inputmethod.InputMethodManager


class KeyboardUtil(private val mContext:Activity) {

//    private var mContext: Activity?=null
    /**
     * 虚拟键盘高度
     */
    var virtualKeyboardHeight = 0

    /**
     * 屏幕高度
     */
    var screenHeight: Int

    /**
     * 屏幕6分之一的高度,作用是防止获取到虚拟键盘的高度
     */
    var screenHeight6: Int
    var rootView: View

    init {


        /**
         * 获取屏幕的高度,该方式的获取不包含虚拟键盘
         */
        screenHeight = mContext.resources.displayMetrics.heightPixels
        screenHeight6 = screenHeight / 6
        rootView = mContext.window.decorView
    }

    /**
     * @param listener
     */
    fun setOnKeyboardChangeListener(listener: KeyboardChangeListener?) {
        //当键盘弹出隐藏的时候会 调用此方法。
        rootView.viewTreeObserver.addOnGlobalLayoutListener(OnGlobalLayoutListener {
            /**
             * 回调该方法时rootView还未绘制,需要设置绘制完成监听
             */
            rootView.post(Runnable {
                val rect = Rect()
                /**
                 * 获取屏幕底部坐标
                 */
                rootView.getWindowVisibleDisplayFrame(rect)
                /**
                 * 获取键盘的高度
                 */
                val heightDifference: Int = screenHeight - rect.bottom
                if (heightDifference < screenHeight6) {
                    virtualKeyboardHeight = heightDifference
//                    if (listener != null) {
//                        listener.onKeyboardHide();
//                    }
                    listener?.onKeyboardHide()
                } else {
                    listener?.onKeyboardShow(heightDifference - virtualKeyboardHeight)
                }
            })
        })
    }

    /**
     * 软键盘状态切换监听
     */
    interface KeyboardChangeListener {
        /**
         * 键盘弹出
         *
         * @param keyboardHight 键盘高度
         */
        fun onKeyboardShow(keyboardHight: Int)

        /**
         * 键盘隐藏
         */
        fun onKeyboardHide()
    }

    companion object {
        /**
         * 显示软键盘
         *
         * @param context 当前Activity
         */
        fun showSoftInput(context: Context) {
            val inputMethodManager: InputMethodManager =
                context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            inputMethodManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS)
        }

        /**
         * 隐藏软键盘
         *
         * @param activity 当前Activity
         */
        fun hideSoftInput(activity: Activity) {
            val inputMethodManager: InputMethodManager =
                activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            inputMethodManager.hideSoftInputFromWindow(
                activity.window.decorView.windowToken, 0
            )
        }

        fun showSoftInput(context: Context, view: View?) {
            val imm: InputMethodManager =
                context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS)
            //imm.showSoftInput(view, InputMethodManager.SHOW_FORCED);
        }

        fun hideSoftInput(context: Context, view: View) {
            val imm: InputMethodManager =
                context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            imm.hideSoftInputFromWindow(view.getWindowToken(), 0) //强制隐藏键盘
        }

        fun isShowSoftInput(context: Context): Boolean {
            val imm: InputMethodManager =
                context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            //获取状态信息
            return imm.isActive() //true 打开
        }

        /**
         * 是否显示,显示则关闭,没显示则显示
         *
         * @param context
         */
        fun isShow(context: Context) {
            val imm: InputMethodManager =
                context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS)
        }
    }
}

1、列表(仿微信)

RvActivity.kt

package com.example.myapplication3

import android.os.Bundle
import android.view.MotionEvent
import android.view.View
import android.view.View.OnTouchListener
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.listener.OnItemClickListener
import com.example.myapplication3.adapter.RvAdapter
import com.example.myapplication3.util.KeyboardUtil
import kotlinx.android.synthetic.main.activity_rv.*

class RvActivity : AppCompatActivity(), OnItemClickListener {

    private val mAdapter by lazy {
        RvAdapter().apply {
            setOnItemClickListener(this@RvActivity)
        }
    }
    private var mPosition_item_content: String? = null
    private var mItemPosition = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_rv)
        init()
    }

    private fun init() {
    	ll_comment.visibility = View.GONE
        val mList: MutableList<String> = ArrayList()
        for (i in 0 until 30) { mList.add("$i.编辑文本") }
        recyclerView.adapter = mAdapter
        mAdapter.setList(mList)

        recyclerView.setOnTouchListener(object :OnTouchListener{
            override fun onTouch(v: View?, event: MotionEvent?): Boolean {
                if (ll_comment.visibility == View.VISIBLE){
                    updateEditTextBodyVisible(View.GONE)
                    return true
                }
                return false
            }
        })

        tv_send_comment.setOnClickListener {

            updateEditTextBodyVisible(View.GONE)

//            if (mPosition_item_content == "29.编辑文本"){
//                textView.visibility = View.GONE
//            }
//            KeyboardUtil.hideSoftInput(this)
//            mList[mItemPosition] = et_comment.text.toString()
//            mAdapter.notifyDataSetChanged()
//            ll_comment.visibility = View.GONE
//            et_comment.setText("")
        }
    }

    override fun onItemClick(adapter: BaseQuickAdapter<*, *>, view: View, position: Int) {

        if (ll_comment.visibility == View.VISIBLE){
            updateEditTextBodyVisible(View.GONE)
            return
        }

        var s = adapter.getItem(position) as String
        if (s == "29.编辑文本") {
            textView.visibility = View.VISIBLE
        }
        mPosition_item_content = s
        mItemPosition = position
        ll_comment.visibility = View.VISIBLE
        et_comment.requestFocus()
        et_comment.setText(s)
        KeyboardUtil.showSoftInput(this)
        val v = adapter.getViewByPosition(position,R.id.tv_content) as TextView
//        //item 底部y坐标
//        val mBottomY: Int = getCoordinateY(view) + view.height
//        view.postDelayed(Runnable {
//            val y = getCoordinateY(ll_comment) - 20
//            //评论时滑动到对应item底部和输入框顶部对齐
//            recyclerView.smoothScrollBy(0, mBottomY - y)
//        }, 300)

        //item 底部y坐标
        val mBottomY: Int = getCoordinateY(v) + v.height
        v.postDelayed(Runnable {
            val y = getCoordinateY(ll_comment) - 20
            //评论时滑动到对应item底部和输入框顶部对齐
            recyclerView.smoothScrollBy(0, mBottomY - y)
        }, 300)
    }

    /**
     * 获取控件左上顶点Y坐标
     * @param view
     * @return
     */
    private fun getCoordinateY(view: View): Int {
        val coordinate = IntArray(2)
        view.getLocationOnScreen(coordinate)
        return coordinate[1]
    }

    fun updateEditTextBodyVisible(visibility:Int){
        if (mPosition_item_content.equals("29.编辑文本")){
            textView.visibility = visibility
        }
        ll_comment.visibility = visibility
        if (View.VISIBLE == visibility){
            ll_comment.requestFocus()
            //弹出键盘
//            CommonUtils.showSoftInput(et_comment.context, et_comment)
            KeyboardUtil.showSoftInput(et_comment.context,et_comment)
        }else if (View.GONE == visibility){
            //隐藏键盘
//            CommonUtils.hideSoftInput(et_comment.context, et_comment)
            KeyboardUtil.hideSoftInput(et_comment.context,et_comment)
        }
    }
}

activity_rv.xml


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <LinearLayout
        android:id="@+id/ll_scroll"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
        <TextView
            android:id="@+id/textView"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:visibility="gone"/>
    LinearLayout>

    <LinearLayout
        android:id="@+id/ll_comment"
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:layout_gravity="bottom"
        android:background="#f6f6f6"
        android:elevation="3dp"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:visibility="visible">

        <EditText
            android:id="@+id/et_comment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerVertical="true"
            android:layout_weight="1"
            android:ellipsize="end"
            android:hint="说点什么"
            android:textColorHint="#a2a2a2"
            android:textSize="13dp" />

        <Button
            android:id="@+id/tv_send_comment"
            android:layout_width="60dp"
            android:layout_height="30dp"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:gravity="center"
            android:paddingLeft="10dp"
            android:paddingTop="5dp"
            android:paddingRight="10dp"
            android:paddingBottom="5dp"
            android:text="发送"
            android:textSize="14sp" />
    LinearLayout>
FrameLayout>

2、从底部弹出列表对话框(仿快手)

DialogActivity.kt

package com.example.myapplication3

import android.os.Bundle
import android.view.Gravity
import android.view.View
import android.view.WindowManager
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import com.example.myapplication3.adapter.RvAdapter
import com.example.myapplication3.util.KeyboardUtil
import kotlinx.android.synthetic.main.activity_dialog.*
import kotlinx.android.synthetic.main.rv_item.view.*
import per.goweii.anylayer.AnyLayer
import per.goweii.anylayer.dialog.DialogLayer
import per.goweii.anylayer.dialog.DialogLayer.OutsideTouchedListener
import per.goweii.anylayer.widget.SwipeLayout

class DialogActivity : AppCompatActivity() {

    private var mPosition_item_content: String? = null
    private var mItemPosition = 0

    private var llComment: LinearLayout? = null

    private var llComment7: LinearLayout? = null
    private var etComment7: EditText? = null

    private var etComment: EditText? = null

    private var etComment3: TextView? = null

    private var dialog: DialogLayer? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
        setContentView(R.layout.activity_dialog)
        val mList: MutableList<String> = ArrayList()
        for (i in 0 until 30) { mList.add("$i.编辑文本") }
        button1.setOnClickListener { showRadListDialog(mList) }
    }

    private fun showRadListDialog(dictList: List<String>) {
        val rvDialog = AnyLayer.dialog()
            .contentView(R.layout.activity_dialog_rv)
            .backgroundDimDefault()
            .gravity(Gravity.BOTTOM)
            .swipeDismiss(SwipeLayout.Direction.BOTTOM)
            .animStyle(DialogLayer.AnimStyle.BOTTOM)
            .backgroundDimAmount(0F)//背景变暗的程度0~1,直接调用到这函数里看文档就即可
        rvDialog.show()
        val mAdapter = RvAdapter()
        val mRecyclerView = rvDialog.getView<RecyclerView>(R.id.recyclerView)
        val textView = rvDialog.getView<TextView>(R.id.textView)
        llComment = rvDialog.getView<LinearLayout>(R.id.ll_comment)
        etComment3 = rvDialog.getView<TextView>(R.id.et_comment3)
        etComment3!!.setOnClickListener {
            dialog = showDialog()
            dialog!!.outsideTouched(OutsideTouchedListener {
                KeyboardUtil.hideSoftInput(this@DialogActivity)
            })
            dialog!!.show()
            etComment7 = dialog!!.getView<EditText>(R.id.et_comment7)
            etComment7?.postDelayed(object : Runnable {
                override fun run() {
                    etComment7!!.requestFocus()
                }
            }, 500)
            KeyboardUtil.showSoftInput(this@DialogActivity)
        }
        mRecyclerView!!.adapter = mAdapter
        mAdapter.setList(dictList)
        mAdapter.setOnItemClickListener { adapter, view, position ->
            dialog = showDialog()
//             AnyLayer.dialog()
//                .compatSoftInput(true)
//                .contentView(R.layout.dialog_et)
//                .backgroundDimDefault()
//                .gravity(Gravity.BOTTOM)
//                .animStyle(DialogLayer.AnimStyle.BOTTOM)
//                .cancelableOnTouchOutside(true) //设置点击浮层以外区域是否可关闭
            dialog!!.outsideTouched(object : OutsideTouchedListener {
                override fun outsideTouched() {
//                    if (mPosition_item_content.equals("29.编辑文本")) {
//                        textView!!.visibility = View.GONE
//                    }
                    KeyboardUtil.hideSoftInput(this@DialogActivity)
                }
            })
            dialog!!.show()
            llComment7 = dialog!!.getView<LinearLayout>(R.id.ll_comment7)
            etComment7 = dialog!!.getView<EditText>(R.id.et_comment7)

            var s = adapter.getItem(position) as String
//            if (s == "29.编辑文本") {
//                textView!!.visibility = View.VISIBLE
//            }
            mPosition_item_content = s
            mItemPosition = position
//            etComment?.postDelayed(Runnable { //给他个延迟时间
            etComment7!!.requestFocus()
//            }, 300)

            etComment7!!.setText(s)
            KeyboardUtil.showSoftInput(this@DialogActivity)
            val v = adapter.getViewByPosition(position,R.id.tv_content) as TextView
            //item 底部y坐标
            val mBottomY: Int = getCoordinateY(v) + v.height
            v.postDelayed(Runnable {
                val y = getCoordinateY(llComment7!!) - 20
                //评论时滑动到对应item底部和输入框顶部对齐
                mRecyclerView.smoothScrollBy(0, mBottomY - y)
            }, 600)
        }
    }

    /**
     * 获取控件左上顶点Y坐标
     * @param view
     * @return
     */
    private fun getCoordinateY(view: View): Int {
        val coordinate = IntArray(2)
        view.getLocationOnScreen(coordinate)
        return coordinate[1]
    }

    private fun showDialog(): DialogLayer {
        return AnyLayer.dialog()
            .compatSoftInput(true)
            .contentView(R.layout.dialog_et)
            .backgroundDimDefault()
            .gravity(Gravity.BOTTOM)
            .animStyle(DialogLayer.AnimStyle.BOTTOM)
            .cancelableOnTouchOutside(true) //设置点击浮层以外区域是否可关闭
            .cancelableOnClickKeyBack(false)
    }
}

activity_dialog.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="从底部弹出列表对话框"/>
RelativeLayout>

activity_dialog_rv.xml


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="500dp"
    android:layout_gravity="bottom">

    <LinearLayout
        android:id="@+id/ll_scroll"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

        <TextView
            android:id="@+id/textView"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:visibility="gone" />

        <LinearLayout
            android:id="@+id/ll_comment"
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:layout_gravity="bottom"
            android:background="@color/purple_200"
            android:gravity="center"
            android:orientation="vertical">

            <TextView
                android:id="@+id/et_comment3"
                android:layout_width="350dp"
                android:layout_height="wrap_content"
                android:background="#DEDEDE"
                android:text="发条有爱评论"/>
        LinearLayout>
    LinearLayout>

















FrameLayout>

dialog_et.xml


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom">

    <LinearLayout
        android:id="@+id/ll_comment7"
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:layout_gravity="bottom"
        android:background="#FF9800"
        android:elevation="3dp"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:visibility="visible">

        <EditText
            android:id="@+id/et_comment7"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerVertical="true"
            android:layout_weight="1"
            android:ellipsize="end"
            android:hint="说点什么"
            android:textColorHint="#a2a2a2"
            android:textSize="13dp" />

        <Button
            android:id="@+id/tv_send_comment"
            android:layout_width="60dp"
            android:layout_height="30dp"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:gravity="center"
            android:paddingLeft="10dp"
            android:paddingTop="5dp"
            android:paddingRight="10dp"
            android:paddingBottom="5dp"
            android:text="发送"
            android:textSize="14sp" />
    LinearLayout>
FrameLayout>

MainActivity.kt

package com.example.myapplication3

import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity :AppCompatActivity(){

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //1、列表
        button1.setOnClickListener {
            val intent = Intent(this@MainActivity, RvActivity::class.java)
            startActivity(intent)
        }
        //2、从底部弹出列表对话框
        button2.setOnClickListener {
            val intent = Intent(this@MainActivity, DialogActivity::class.java)
            startActivity(intent)
        }
    }
}

activity_main.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">

    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="@color/red"
        android:text="仿微信快手点击列表item后弹出输入框,所item自动滚动到输入框上方"/>

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/tv"
        android:text="1、列表(仿微信)"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/button1"
        android:text="2、从底部弹出列表对话框(仿快手)"/>
RelativeLayout>

你可能感兴趣的:(Android,kotlin开源项目-功能,kotlin,RecyclerView,AnyLayer,EditText,item自动滚动到输入框上方)