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