Android自定义侧滑Item

news2024/12/24 11:32:29

源码地址: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
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/853533.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python怎么判断变量的数据类型

在编程的世界里&#xff0c;了解各种数据类型是非常重要的。在Python中&#xff0c;有着丰富的数据类型用于存储和处理不同类型的数据。掌握这些数据类型的定义和作用&#xff0c;我们能够更好地在程序中管理和操作数据&#xff0c;提高代码的效率和可读性。 Python中常见的数据…

使用node搭建服务器,前端自己写接口,将vue或react打包后生成的dist目录在本地运行

使用node.jsexpress或者使用node.jspm2搭建服务器&#xff0c;将vue或react打包后生成的dist目录在本地运行 vue项目打包后生成的dist目录如果直接在本地打开index.html,在浏览器中会报错&#xff0c;无法运行起来。 通常我是放到后端搭建的服务上面去运行&#xff0c;当时前端…

pve和openwrt以及我的电脑中网络的关系和互通组网

情况1 一台主机 有4个口&#xff0c;分别eth0,eth1,eth2,eth3 pve有管理口 这个情况下 &#xff0c;没有openwrt 直接电脑和pve管理口连在一起就能进pve管理界面 情况2 假设pve 的管理口味eth0 openwrt中桥接的是eth0 eth1 eth2 那么电脑连接eth3或者pve管理口设置eth3&#xf…

jmeter创建一个压测项目

1.jemeter新建一个项目&#xff1a; 2.接下来对Thread进行描述&#xff0c;也可以先使用默认的Thread进行操作。 3.添加http请求头的信息。按照如图所示操作 4.在请求头里面添加必要的字段&#xff0c;可以只填必要字段就可以 5.添加Http请求信息&#xff0c;如下图&#xff…

【webpack】动态配置cdn,多模板入口项目搭建

动态配置多模板 按照这个模板创建项目 安装glob,获取目录下的文件名称 封装方法utilsConfig&#xff0c;动态生产 page // pages 多入口配置 const path require("path");// glob 是 webpack 安装时依赖的一个第三方模块&#xff0c;该模块允许你使用 * 等符号, …

图片如何转pdf?几个小妙招了解一下

图片如何转pdf&#xff1f;在日常工作和生活中&#xff0c;我们经常需要将图片转换成PDF格式&#xff0c;以便于我们进行存档、传输或打印。那么&#xff0c;如何快速、方便地将图片转换成PDF呢&#xff1f;这里介绍就为大家介绍几款好用的工具。 我们可以使用【迅捷PDF转换器】…

opencv动态目标检测

文章目录 前言一、效果展示二、实现方法构造形态学操作所需的核:创建背景减除模型:形态学操作:轮廓检测: 三、代码python代码C代码 总结参考文档 前言 很久没更新文章了&#xff0c;这次因为工作场景需要检测动态目标&#xff0c;特此记录一下。 一、效果展示 二、实现方法 基…

简化AD管理减少IT工作负担

管理和保护混合 AD 环境 IT 管理员几乎每天都要创建和管理多个 AD 对象&#xff0c;利用本机AD工具&#xff08;如Active Directory用户和计算机控制台以及PowerShell脚本&#xff09;来执行这些任务并不理想&#xff0c;因为它们必须在多个控制台之间切换才能执行这些任务&am…

【UE4 RTS】02-Camera Movement

前言 本篇实现了CameraPawn的基本移动功能 步骤 1. 打开项目设置&#xff0c;在 引擎——输入 一栏中删除模板自带的操作映射 在轴映射中&#xff0c;删除“TurnRate” 添加如下键值 2. 打开“RTS_PlayerController_BP”&#xff0c;在事件图表中添加如下节点 此时运行游戏就…

MySQL和钉钉单据接口对接

MySQL和钉钉单据接口对接 数据源系统:钉钉 钉钉&#xff08;DingTalk&#xff09;是阿里巴巴集团打造的企业级智能移动办公平台&#xff0c;是数字经济时代的企业组织协同办公和应用开发平台。钉钉将IM即时沟通、钉钉文档、钉闪会、钉盘、Teambition、OA审批、智能人事、钉工牌…

Java后台生成ECharts图片

前言 通过echarts的jar包&#xff0c;Java后台生成一张图片&#xff0c;并把图片插入到word中。关于word插图片的代码在下一章。 需要用到的工具PhantomJS,Echarts-convert.js,jquery.js,echarts.js。 1.PhantomJS 介绍 PhantomJS是一个不需要浏览器的富客户端。 官方介绍&…

PS的一些智能对象是怎么用的?用于包装设计该怎么使用?

大家都对一些效果图不太理解&#xff0c;我现在就献丑给大家讲一下&#xff0c;教程都是网友盛传的&#xff0c;我自己学习并且有所体会。 一般做的非常好的PS效果图都是外国人自己做的&#xff0c;所以大多数效果图都是英文&#xff0c;细心的网友会发现&#xff0c;中文的是一…

IOS上架流程

IOS上架流程 准备 开发者账号完工的项目 上架步骤 一、创建App ID二、创建证书请求文件 &#xff08;CSR文件&#xff09;三、创建发布证书 &#xff08;CER&#xff09;四、创建Provisioning Profiles配置文件 &#xff08;PP文件&#xff09;五、在App Store创建应用六、…

MPLAB X IDE v6.1.0 使用MCC代码配置器

安装教程应该很好搜到&#xff0c;如果没有 代码配置器&#xff08;MPLAB Code Configurator&#xff0c;MCC&#xff09;说明IDE版本太低了&#xff0c;建议更新下版本&#xff1b; 刚安装完成之后第一次启动会很卡&#xff0c;属于正常现象&#xff1b; 我这好像是离线模式…

博客网站添加复制转载提醒弹窗Html代码

网站如果是完全禁止右键&#xff08;复制、另存为等&#xff09;操作&#xff0c;对用户来说体验感会降低&#xff0c;但是又不希望自己的原创内容直接被copy&#xff0c;今天飞飞和你们分享几行复制转载提醒弹窗Html代码。 效果展示&#xff1a; 复制以下代码&#xff0c;将其…

11_Vue3中的新的组件

1. Fragment 在Vue2中&#xff1a;组件必须要有一个跟标签在Vue3中&#xff1a;组件可以没有根标签&#xff0c;内部会将多个标签包含在一个Fragment虚拟元素中好处&#xff1a;减少标签层级&#xff0c;减少内存占用 2. Teleport 什么是Teleport?——Teleport 是一种能够将…

ubuntu22.04源码编译opencv4.6

第一次编译之后&#xff0c;测试opencv_example不成功&#xff0c;又重新卸载了再装了一次&#xff0c;成功了&#xff0c;简单记录一下。 下载opencv4.6以及opencv_contrib-4.6.0 opencv下载地址 opencv-contrib下载地址解压以后&#xff0c;把contrib放到opencv4.6文件夹下 第…

无涯教程-Perl - getnetent函数

描述 此函数从/etc/networks文件获取下一个条目,返回-($name,$aliases,$addrtype,$net) 如果/etc/networks文件为空,则它将不返回任何内容,并且调用将失败。 语法 以下是此函数的简单语法- getnetent返回值 此函数在错误时返回undef,否则在标量context中返回网络地址,在错…

Qt应用开发(基础篇)——框架类 QFrame

一、前言 QFrame继承于QWidget&#xff0c;被QLCDNumber、QToolBox、QLabel、QListView等部件继承&#xff0c;是一个拥有矩形框架的基类。 QFrame可以直接创建成一个没有内容的的矩形框架&#xff0c;框架的样式由边框厚度(lineWidth)、框架形状(QFrame::Shape)和阴影样式(QFr…

药物临床试验项目风险管理︱科济生物医药临床运营部总监张立峰

科济生物医药&#xff08;上海&#xff09;有限公司临床运营部总监张立峰先生受邀为由PMO评论主办的2023第十二届中国PMO大会演讲嘉宾&#xff0c;演讲议题&#xff1a;药物临床试验项目风险管理---回顾疫情考验下的风险管理应对。大会将于8月12-13日在北京举办&#xff0c;敬请…