Android kotlin 实现频道管理功能

文章目录

  • 一、实现效果
  • 二、引入依赖
  • 三、源码实现
    • 1、实体类
    • 2、适配器
    • 3、拖拽事件(ItemTouchHelper.Callback())
    • 4、视图实现

一、实现效果

二、引入依赖

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"

三、源码实现

1、实体类

MySection.java

package com.example.myapplication3.entity;

import com.chad.library.adapter.base.entity.JSectionEntity;

public class MySection extends JSectionEntity {

    private boolean isHeader;
    private int headerNum;
    private Object object;

    private boolean isRecommend;

    public MySection(boolean isHeader, int headerNum, Object object,boolean isRecommend) {
        this.isHeader = isHeader;
        this.headerNum = headerNum;
        this.object = object;
        this.isRecommend = isRecommend;
    }

    public Object getObject() {
        return object;
    }

    @Override
    public boolean isHeader() {
        return isHeader;
    }

    public int getHeaderNum() {
        return headerNum;
    }

    public boolean isRecommend() {
        return isRecommend;
    }

    public void setRecommend(boolean recommend) {
        isRecommend = recommend;
    }
}

2、适配器

SectionQuickAdapter.kt

package com.example.myapplication3.adapter

import android.animation.Animator
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.graphics.Color
import android.text.Html
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import com.chad.library.adapter.base.BaseSectionQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.example.myapplication3.R
import com.example.myapplication3.entity.MySection
import kotlinx.android.synthetic.main.def_section_head.view.*
import java.util.*

class SectionQuickAdapter(layoutResId: Int, sectionHeadResId: Int, data: MutableList<MySection>) :
    BaseSectionQuickAdapter<MySection, BaseViewHolder>(sectionHeadResId, data) {
    init {
        setNormalLayout(layoutResId)
        addChildClickViewIds(R.id.edit)
    }

    var selectedSize: Int = 0             //已选
    var fixSize: Int = 0                 //固定频道数目
    var isRecommend: Boolean = true      //当前是否显示推荐频道
    var mLeft: Int = -1                  //推荐频道蓝色线条距离屏幕左边的距离
    var mRight: Int = -1                 //城市频道蓝色线条距离屏幕左边的距离
    var mTabY: Int = 0                   //tab距离parent的Y的距离

//    var onItemRangeChangeListener: SectionQuickAdapter.OnItemRangeChangeListener? = null

    override fun convertHeader(helper: BaseViewHolder, item: MySection) {
        helper.itemView.run {
            when (item.headerNum) {
                1 -> {
                    header.text = "我最喜欢 "
//                    enter.text = Html.fromHtml("按住拖动可以排序")
                }
                2 -> {
                    header.text = Html.fromHtml("全部频道 点击添加频道")
                    edit.visibility = View.GONE
                }
            }
        }
    }

    override fun convert(holder: BaseViewHolder, item: MySection) {
        setChannel(holder, holder.adapterPosition, item)
    }

    private fun setChannel(holder: BaseViewHolder, position: Int, item: MySection) {
        var name = holder.getView<TextView>(R.id.item_textView)
        var delete = holder.getView<ImageView>(R.id.delete)
        var add = holder.getView<TextView>(R.id.tv_add)
        name.text = item.`object` as String
        name.setOnClickListener {
            if (holder.layoutPosition < selectedSize + 1) {
                //tab上面的 点击移除
                if (holder.layoutPosition > fixSize) {
                    removeFromSelected(holder)
                }
            } else {
                //tab下面的 点击添加到已选频道
                selectedSize++
                itemMove(holder.layoutPosition, selectedSize)
                notifyItemChanged(selectedSize)
                //刷新itemDecoration
//                onItemRangeChangeListener?.let { onItemRangeChangeListener!!.refreshItemDecoration() }
            }
        }
        name.setOnLongClickListener {
            true
        }

        delete.setOnClickListener { removeFromSelected(holder) }
        //tab下面及固定频道不显示删除按钮
        if (position - 1 < fixSize || position > selectedSize) {

            //************************新代码**********************
            //固定频道的文字灰色
            if (fixSize == position) {
                name.setTextColor(Color.GRAY)
            } else {
                add.visibility = View.VISIBLE
            }
            //****************************************************

            delete.visibility = View.GONE
        } else {
            delete.visibility = View.VISIBLE

            //************************新代码**********************
            add.visibility = View.GONE
            //****************************************************
        }
    }

//    private fun setTab(holder: ChannelAdapter.TabHolder) {
//        holder.itemView.viewTreeObserver.addOnPreDrawListener(object :
//            ViewTreeObserver.OnPreDrawListener {
//            override fun onPreDraw(): Boolean {
//                mTabY = holder.itemView.top
//                return true
//            }
//
//        })
//    }

    private fun removeFromSelected(holder: BaseViewHolder) {
        val delete = holder.getView<ImageView>(R.id.delete)

        //************************新代码**********************
        val add = holder.getView<TextView>(R.id.tv_add)
        add.visibility = View.VISIBLE
        //****************************************************

        delete.visibility = View.GONE
        val position = holder.layoutPosition
        val bean = data[position]

        if ((isRecommend && bean.isRecommend) || (!isRecommend && !bean.isRecommend)) {
            //移除的频道属于当前tab显示的频道,直接调用系统方法移除
            itemMove(position, selectedSize + 1)
            notifyItemRangeChanged(selectedSize + 1, 1)
            //刷新itemDecoration
//            onItemRangeChangeListener?.let { onItemRangeChangeListener!!.refreshItemDecoration() }
        } else {
            //不属于当前tab显示的频道
            removeAnimation(
                holder.itemView,
                (if (isRecommend) mRight else mLeft).toFloat(),
                mTabY.toFloat(),
                position
            )
        }
        selectedSize--
    }

    private fun removeAnimation(view: View, x: Float, y: Float, position: Int) {
        val fromX = view.left
        val fromY = view.top
        val animatorX = ObjectAnimator.ofFloat(view, "translationX", 0f, x - fromX)
        val animatorY = ObjectAnimator.ofFloat(view, "translationY", 0f, y - fromY)
        val alpha = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f)
        val set = AnimatorSet()
        set.playTogether(animatorX, animatorY, alpha)
        set.duration = 350
        set.addListener(object : Animator.AnimatorListener {
            override fun onAnimationRepeat(animation: Animator?) {
            }

            override fun onAnimationCancel(animation: Animator?) {
            }

            override fun onAnimationStart(animation: Animator?) {
            }

            override fun onAnimationEnd(animation: Animator?) {
                data.add(0, data[position])
                data.removeAt(position)
                notifyItemRemoved(position)
//                onItemRangeChangeListener?.let { onItemRangeChangeListener!!.refreshItemDecoration() }
                //这里需要重置view的属性
                resetView(view, x - fromX, y - fromY)
            }
        })
        set.start()
    }

    private fun resetView(view: View, toX: Float, toY: Float) {
        val animatorX = ObjectAnimator.ofFloat(view, "translationX", -toX, 0f)
        val animatorY = ObjectAnimator.ofFloat(view, "translationY", -toY, 0f)
        val alpha = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f)
        val set = AnimatorSet()
        set.playTogether(animatorX, animatorY, alpha)
        set.duration = 0
        set.startDelay = 5
        set.start()
    }

    fun itemMove(fromPosition: Int, toPosition: Int) {

        if (fromPosition < toPosition) {
            for (i in fromPosition until toPosition) {
                Collections.swap(data, i, i + 1)
            }
        } else {
            for (i in fromPosition downTo toPosition + 1) {
                Collections.swap(data, i, i - 1)
            }
        }
        notifyItemMoved(fromPosition, toPosition)
    }
}

3、拖拽事件(ItemTouchHelper.Callback())

item拖拽,文件DragTouchHelper.kt

package com.example.myapplication3.widget

import android.graphics.Canvas
import android.graphics.Color
import android.graphics.DashPathEffect
import android.graphics.Paint
import android.graphics.drawable.GradientDrawable
import android.util.Log
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter.base.dragswipe.DragAndSwipeCallback
import com.chad.library.adapter.base.module.BaseDraggableModule
import com.example.myapplication3.R
import com.example.myapplication3.past.ChannelRvAdapter1
import com.example.myapplication3.past.DragAdapter
import com.example.myapplication3.adapter.SectionQuickAdapter
import com.example.myapplication3.entity.MySection
import java.util.*

/**
 * GitHub : https://github.com/yechaoa
 * CSDN : http://blog.csdn.net/yechaoa
 *
 * Created by yechao on 2022/7/17.
 * Describe :
 */

class ItemDragCallback2(var mAdapter: SectionQuickAdapter, var mPadding: Int) : ItemTouchHelper.Callback()
{
    private val mPaint: Paint = Paint()

    init {
        mPaint.color = Color.GRAY
        mPaint.isAntiAlias = true
        mPaint.strokeWidth = 1f
        mPaint.style = Paint.Style.STROKE
        val pathEffect = DashPathEffect(FloatArray(2, { 5f }), 5f)
        mPaint.pathEffect = pathEffect
    }

    override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
        //固定位置及tab下面的channel不能拖动
        val position = viewHolder!!.layoutPosition
        if (position < mAdapter.fixSize + 1 || position > mAdapter.selectedSize) {
            return makeMovementFlags(0, 0)
        }
        val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
        return makeMovementFlags(dragFlags, 0)
    }

    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
        val fromPosition = viewHolder!!.layoutPosition    //拖动的位置
        val toPosition = target!!.layoutPosition         //释放的位置
        //固定位置及tab下面的channel不能移动
        if (toPosition < mAdapter.fixSize + 1 || toPosition > mAdapter.selectedSize) {
            return false
        }
        mAdapter.itemMove(fromPosition, toPosition)
        return true
    }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
        //滑动重写这里
    }

    override fun onChildDrawOver(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder?, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
        super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
//        if (dX != 0f && dY != 0f || isCurrentlyActive) {
//            //长按拖拽时底部绘制一个虚线矩形
//            c!!.drawRect(viewHolder!!.itemView.left.toFloat(), (viewHolder.itemView.top - mPadding).toFloat(), viewHolder.itemView.right.toFloat(), viewHolder.itemView.bottom.toFloat(), mPaint)
//        }
    }

    override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
        super.onSelectedChanged(viewHolder, actionState)
        if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
            //长按时调用 设置颜色 阴影
//            val holder = viewHolder as ChannelAdapter.ChannelHolder
//            holder.name.setBackgroundColor(Color.parseColor("#FDFDFE"))
//            holder.delete.visibility= View.GONE
//            holder.name.elevation=5f
            //*******新代码********
            super.onSelectedChanged(viewHolder, actionState)
            //*******新代码********
        }
    }

    override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
        super.clearView(recyclerView, viewHolder)
        //重置view
//        val holder=viewHolder as ChannelAdapter.ChannelHolder
//        holder.name.setBackgroundColor(Color.parseColor("#f0f0f0"))
//        holder.delete.visibility= View.VISIBLE
//        holder.name.elevation=0f
        //*******新代码********
        super.clearView(recyclerView, viewHolder)
        //*******新代码********

    }
}

4、视图实现

ChannelActivity.kt

package com.example.myapplication3.channel

import android.os.Bundle
import android.view.Gravity
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.example.myapplication3.R
import com.example.myapplication3.adapter.SectionQuickAdapter
import com.example.myapplication3.entity.MySection
import com.example.myapplication3.widget.ItemDragCallback2
import kotlinx.android.synthetic.main.activity_channel.*
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 ChannelActivity : AppCompatActivity()
//    , SectionQuickAdapter.OnItemRangeChangeListener
{

    private var mRecyclerView: RecyclerView? = null

    companion object {
        private var SPAN_COUNT = 4
    }

    private var list: MutableList<MySection> = ArrayList()
    private var itemTouchHelper: ItemTouchHelper? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_channel)
        button.setOnClickListener {
            showRadListDialog(initData())
        }
    }

    private fun showRadListDialog(mList: MutableList<MySection>) {
        val rvDialog = AnyLayer.dialog()
            .contentView(R.layout.activity_section_uer)
            .backgroundDimDefault()
            .gravity(Gravity.BOTTOM)
            .swipeDismiss(SwipeLayout.Direction.BOTTOM)
            .animStyle(DialogLayer.AnimStyle.BOTTOM)
            .backgroundDimAmount(0.5F)//背景变暗的程度0~1,直接调用到这函数里看文档就即可
        rvDialog.outsideTouched(OutsideTouchedListener {
            mList.clear()
        })
        rvDialog.show()
        mRecyclerView = rvDialog.getView<RecyclerView>(R.id.rv_list)
        mRecyclerView?.layoutManager = GridLayoutManager(this, SPAN_COUNT)
        val mAdapter = SectionQuickAdapter(R.layout.item_drag_grid, R.layout.def_section_head, mList)
//        val animator = DefaultItemAnimator()
//        animator.moveDuration = 400      //设置动画时间
//        animator.removeDuration = 0
//        mRecyclerView?.itemAnimator = animator
        mRecyclerView?.adapter = mAdapter
        mAdapter.fixSize = 1
        mAdapter.selectedSize = 10 //点击进入频道下面的频道数
//        mAdapter.onItemRangeChangeListener = this
        // 设置拖拽
        val dragCallBack = ItemDragCallback2(mAdapter,2)
        itemTouchHelper = ItemTouchHelper(dragCallBack)
        itemTouchHelper!!.attachToRecyclerView(mRecyclerView)
    }

    private fun initData(): MutableList<MySection> {
        list.add(MySection(true, 1, "我最喜欢 点击进入频道", false))
        list.add(MySection(false, 0, "测试1", true))
        list.add(MySection(false, 0, "测试2", true))
        list.add(MySection(false, 0, "测试3", true))
        list.add(MySection(false, 0, "测试4", true))
        list.add(MySection(false, 0,"测试5",true))
        list.add(MySection(false, 0,"测试6",true))
        list.add(MySection(false, 0,"测试7",true))
        list.add(MySection(false, 0,"测试8",true))
        list.add(MySection(false, 0,"测试9",true))
        list.add(MySection(false, 0,"测试10",true))

        list.add(MySection(true, 2, "全部频道 点击添加频道", false))
        list.add(MySection(false, 0, "测试11", true))
        list.add(MySection(false, 0, "测试12", true))
        list.add(MySection(false, 0, "测试13", true))
        list.add(MySection(false, 0, "测试14", true))
        list.add(MySection(false, 0,"测试15",true))
        list.add(MySection(false, 0,"测试16",true))
        list.add(MySection(false, 0,"测试17",true))
        list.add(MySection(false, 0,"测试18",true))
        list.add(MySection(false, 0,"测试19",true))
        list.add(MySection(false, 0,"测试20",true))
        return list
    }

//    override fun refreshItemDecoration() {
//        mRecyclerView?.invalidateItemDecorations()
//    }
}

activity_section_uer.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="700dp"
    android:background="@color/white">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
LinearLayout>

item_drag_grid.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="75dp"
    android:layout_height="50dp">

    <TextView
        android:id="@+id/item_textView"
        android:layout_width="60dp"
        android:layout_height="30dp"
        android:layout_centerInParent="true"
        android:background="@drawable/shape_radius5_green"
        android:gravity="center"
        android:text="测试"
        android:textColor="@color/black"
        android:textSize="13dp"/>

    <ImageView
        android:id="@+id/delete"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_alignParentRight="true"
        android:src="@mipmap/delete"
        android:visibility="visible"/>

    <TextView
        android:id="@+id/tv_add"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_alignRight="@id/item_textView"
        android:layout_alignParentRight="true"
        android:layout_marginTop="8dp"
        android:text="+"
        android:visibility="gone"/>
RelativeLayout>

Android kotlin 实现频道管理功能_第1张图片
shape_radius5_green.xml


<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/bg" />
    <corners android:radius="5dp" />
shape>
<color name="bg">#E7E7E7color>

def_section_head.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:padding="10dp">

    <TextView
        android:id="@+id/header"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:text="已选频道 "
        android:textStyle="bold"/>








    <TextView
        android:id="@+id/edit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:textColor="@color/red"
        android:text="按住拖动可以排序" />
RelativeLayout>

你可能感兴趣的:(Android,kotlin开源项目-功能,RecyclerView,BRVAH3.0.6,BSQA,androidx,AnyLayer)