

源码地址:https://github.com/LanSeLianMa/CustomizeView/tree/master/cehuaitem
使用方式一:XML布局中直接使用
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <com.test.festec.cehuaitem.widget.SideslipContainer
        android:id="@+id/sideslip_container01"
        android:layout_width="match_parent"
        android:layout_height="70dp"
        app:option_width="65dp">
        <com.test.festec.cehuaitem.widget.SideslipContent
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <TextView
                android:background="@color/d5"
                android:paddingTop="20dp"
                android:textAlignment="center"
                android:textSize="20sp"
                android:text="content"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </com.test.festec.cehuaitem.widget.SideslipContent>
        <com.test.festec.cehuaitem.widget.SideslipOption
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@color/blue"
            android:tag="add"
            android:text="增加" />
        <com.test.festec.cehuaitem.widget.SideslipOption
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@color/orange"
            android:tag="edit"
            android:text="编辑" />
        <com.test.festec.cehuaitem.widget.SideslipOption
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@color/red"
            android:tag="delete"
            android:text="删除" />
    </com.test.festec.cehuaitem.widget.SideslipContainer>
</LinearLayout>
Activity中监听
class MainActivity : Activity() {
    private lateinit var binding: ActivityMainBinding
    private var options = mutableListOf("增加", "编辑", "删除")
    private var optionBg = mutableListOf(R.color.blue, R.color.orange, R.color.red)
    @SuppressLint("UseCompatLoadingForDrawables")
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.sideslipContainer01.addOnClickListener(object : SideslipContainer.SideslipContainerOnClick {
            override fun optionOnClick(optionTag: Any) {
                Toast.makeText(this@MainActivity,"optionTag:$optionTag", Toast.LENGTH_SHORT).show()
                binding.sideslipContainer01.sideslipRecover()
            }
            override fun contentOnClick() {
                Toast.makeText(this@MainActivity,"content", Toast.LENGTH_SHORT).show()
                binding.sideslipContainer01.sideslipRecover()
            }
        })
    }
}使用方式二:代码方式使用
先定义一个容器
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <LinearLayout
        android:id="@+id/container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical" />
</LinearLayout>
Activity中动态添加
class MainActivity : Activity() {
    private lateinit var binding: ActivityMainBinding
    private var options = mutableListOf("增加", "编辑", "删除")
    private var optionBg = mutableListOf(R.color.blue, R.color.orange, R.color.red)
    @SuppressLint("UseCompatLoadingForDrawables")
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        // 创建侧滑容器,配置基础参数
        val sideslip = SideslipContainer(this, DensityUtil.dp2px(this, 65f))
        val layoutParams = LinearLayout.LayoutParams(
            LinearLayout.LayoutParams.MATCH_PARENT,
            DensityUtil.dp2px(this, 70f)
        )
        sideslip.layoutParams = layoutParams
        // 创建侧滑内容
        val content = SideslipContent(this).apply {
            background = resources.getDrawable(R.color.black,null)
        }
        // 加入侧滑容器中
        sideslip.addView(content)
        // 创建选项卡,并加入侧滑容器中
        options.forEachIndexed { index, str ->
            val option = SideslipOption(this,str)
            option.text = str
            option.background = resources.getDrawable(optionBg[index], null)
            sideslip.addView(option)
        }
        // 点击监听
        sideslip.addOnClickListener(object : SideslipContainer.SideslipContainerListener {
            override fun optionOnClick(optionTag: Any) {
                Log.e("TAG","optionTag:$optionTag")
            }
            override fun contentOnClick() {
                Log.e("TAG","content")
            }
        })
        binding.container.addView(sideslip)
    }
}使用方式三:结合RecyclerView使用
重写LayoutManager
// 重写LayoutManager,动态让RecyclerView 禁止/恢复 Y轴滚动
open class CustomLinerLayoutManager(context: Context) : LinearLayoutManager(context) {
    private var isScrollEnabled = true
    fun getEnabled(): Boolean {
        return isScrollEnabled
    }
    fun setScrollEnabled(flag: Boolean) {
        isScrollEnabled = flag
    }
    override fun canScrollVertically(): Boolean {
        return isScrollEnabled && super.canScrollVertically();
    }
}重写RecyclerView
class MyRecyclerView : RecyclerView {
    constructor(context: Context) : super(context)
    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
    init {
        addOnScrollListener(object : RecyclerView.OnScrollListener() {
            /**
             *
             * public static final int SCROLL_STATE_IDLE = 0;  :  RecyclerView 当前未滚动。
             *
             * public static final int SCROLL_STATE_DRAGGING = 1;  :  RecyclerView 当前正在被外部输入(例如用户触摸输入)拖动。
             *
             * public static final int SCROLL_STATE_SETTLING = 2;  :  RecyclerView 当前正在动画到最终位置,而不是在外部控制。
             */
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                    childrenRecover()
                }
            }
        })
    }
    // view初始化
    private var viewInit = false
    // 上一会触摸的子View
    var originalChild: SideslipContainer? = null
    // 当前触摸的子View
    var currentChild: SideslipContainer? = null
    private var customLayoutManager: CustomLinerLayoutManager? = null
    private var childMoveCallback = object : ChildOnTouchCallback {
        override fun currentChildMove() {
            childrenRecover()
        }
        override fun originalChild(originalSideslip: SideslipContainer?) {
            originalChild = originalSideslip
        }
        override fun currentChild(currentContainer: SideslipContainer?) {
            currentChild = currentContainer
        }
        override fun listStopYScroll() {
            // Log.e("TAG", "List停止滚动")
            if (customLayoutManager!!.getEnabled()) {
                customLayoutManager?.setScrollEnabled(false)
            }
        }
        override fun listRecoverYScroll() {
            // Log.e("TAG", "List恢复滚动")
            if (!(customLayoutManager!!.getEnabled())) {
                customLayoutManager?.setScrollEnabled(true)
            }
        }
    }
    // 子View恢复
    private fun childrenRecover() {
        children.forEach {
            (it as SideslipContainer).sideslipRecover()
        }
    }
    override fun onViewAdded(child: View?) {
        // Log.e("TAG","onViewAdded")
        val sideslipContainer = (child as SideslipContainer)
        sideslipContainer.addOnChildMoveCallback(childMoveCallback)
    }
    // 当复用item,彻底超出屏幕,不可见时执行
    override fun onViewRemoved(child: View?) {
        // Log.e("TAG","onViewRemoved")
        (child as SideslipContainer).sideslipStateRest()
    }
    override fun onWindowFocusChanged(hasWindowFocus: Boolean) {
        // Log.e("TAG","onWindowFocusChanged")
        super.onWindowFocusChanged(hasWindowFocus)
        if (!viewInit) {
            customLayoutManager = (layoutManager as CustomLinerLayoutManager)
        }
        viewInit = true
    }
    interface ChildOnTouchCallback {
        // 有子View侧滑了
        fun currentChildMove()
        // 上一个触摸的子View
        fun originalChild(originalSideslip: SideslipContainer?)
        // 当前触摸的子View
        fun currentChild(currentContainer: SideslipContainer?)
        // 列表停止Y轴滚动
        fun listStopYScroll()
        // 列表恢复Y轴滚动
        fun listRecoverYScroll()
    }
}RecyclerView适配器
class MyListAdapter(
    var context: Context,
    var data: MutableList<Info>
) : RecyclerView.Adapter<MyListAdapter.MyViewHolder>() {
    private var options = mutableListOf("增加", "编辑", "删除")
    private var optionBg =
        mutableListOf(R.color.blue, R.color.orange, R.color.red)
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val itemView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false)
        val sideslip = sideslipContainer(itemView)
        return MyViewHolder(sideslip)
    }
    @SuppressLint("UseCompatLoadingForDrawables", "ResourceAsColor")
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val sideslip = holder.itemView as SideslipContainer
        // 根据不同权限,添加不同的选项卡
        val optionsView = mutableListOf<SideslipOption>()
        if (data[position].level == 0) {
            optionsView.clear()
        } else if (data[position].level == 1) {
            val option = SideslipOption(context, options[1])
            option.text = options[1]
            option.background = context.resources.getDrawable(optionBg[1], null)
            optionsView.add(option)
        } else {
            options.forEachIndexed { index, str ->
                val option = SideslipOption(context, str)
                option.text = str
                option.background = context.resources.getDrawable(optionBg[index], null)
                optionsView.add(option)
            }
        }
        sideslip.addMultipleOption(optionsView)
        // 点击回调
        sideslip.addOnClickListener(object : SideslipContainer.SideslipContainerOnClick {
            override fun optionOnClick(optionTag: Any) {
                Toast.makeText(context,"${holder.adapterPosition} -- optionTag:$optionTag",Toast.LENGTH_SHORT).show()
                sideslip.sideslipRecover()
            }
            override fun contentOnClick() {
                Toast.makeText(context,"${holder.adapterPosition} - content",Toast.LENGTH_SHORT).show()
                sideslip.sideslipRecover()
            }
        })
        holder.idTv.text = data[position].id.toString()
        holder.titleTv.text = data[position].title
        holder.describeTv.text = data[position].describe
    }
    override fun getItemCount(): Int {
        return data.size
    }
    @SuppressLint("UseCompatLoadingForDrawables")
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private fun sideslipContainer(itemView: View): SideslipContainer {
        // 创建侧滑容器,配置基础参数
        val sideslip = SideslipContainer(context)
        sideslip.setOptionWidth(DensityUtil.dp2px(context, 65f))
        val layoutParams = LinearLayout.LayoutParams(
            LinearLayout.LayoutParams.MATCH_PARENT,
            DensityUtil.dp2px(context, 70f)
        )
        sideslip.layoutParams = layoutParams
        // 创建侧滑内容
        val content = SideslipContent(context)
        content.addView(itemView)
        // 加入侧滑容器中
        sideslip.addView(content)
        // 创建选项卡,并加入侧滑容器中
        // options.forEachIndexed { index, str ->
        //    val option = SideslipOption(context, str)
        //    option.text = str
        //    option.background = context.resources.getDrawable(optionBg[index], null)
        //    sideslip.addView(option)
        // }
        return sideslip
    }
    class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var idTv: TextView
        var titleTv: TextView
        var describeTv: TextView
        init {
            idTv = itemView.findViewById(R.id.id_tv)
            titleTv = itemView.findViewById(R.id.title_tv)
            describeTv = itemView.findViewById(R.id.describe_tv)
        }
    }
}Activity中绑定数据
class ListActivity : Activity() {
    private lateinit var binding: ListLayoutBinding
    private val data: MutableList<Info> = mutableListOf(
        Info(0, "title", "content", 2),
        Info(1, "title", "content", 1),
        Info(2, "title", "content", 2),
        Info(3, "title", "content", 2),
        Info(4, "title", "content", 2),
        Info(5, "title", "content", 1),
        Info(6, "title", "content", 1),
        Info(7, "title", "content", 2),
        Info(8, "title", "content", 2),
        Info(9, "title", "content", 1),
        Info(10, "title", "content", 1),
        Info(11, "title", "content", 2),
        Info(12, "title", "content", 2),
        Info(13, "title", "content", 1),
        Info(14, "title", "content", 1),
        Info(15, "title", "content", 2),
        Info(16, "title", "content", 2),
        Info(17, "title", "content", 2),
        Info(18, "title", "content", 2),
        Info(19, "title", "content", 1),
        Info(20, "title", "content", 2),
        Info(21, "title", "content", 1),
        Info(22, "title", "content", 2),
        Info(23, "title", "content", 2),
        Info(24, "title", "content", 2),
        Info(25, "title", "content", 1),
        Info(26, "title", "content", 2),
        Info(27, "title", "content", 1),
        Info(28, "title", "content", 2),
        Info(29, "title", "content", 2),
        Info(30, "title", "content", 2),
        Info(31, "title", "content", 1),
        Info(32, "title", "content", 1),
        Info(33, "title", "content", 2),
        Info(34, "title", "content", 2),
        Info(35, "title", "content", 1),
    )
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ListLayoutBinding.inflate(layoutInflater)
        setContentView(binding.root)
        val adapter = MyListAdapter(this, data)
        val linearLayoutManager = CustomLinerLayoutManager(this)
        binding.root.layoutManager = linearLayoutManager
        binding.root.adapter = adapter
    }
}


















