Kotlin binding+RecyclerView实现支付宝首页更多、应用编辑界面

主菜单页面布局与交互设计
本文介绍了一个Android应用的主菜单页面布局实现方案及交互设计思路,包括XML布局文件、自定义控件、适配器及监听器等组件的设计与实现细节。

activity 主布局页面:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg_white"
    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/title"
        android:layout_width="fill_parent"
        android:layout_height="48dp"
        android:background="@color/colorBase" >

        <TextView
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:text="@string/app_title"
            android:layout_marginLeft="20dp"
            android:layout_gravity="center_vertical"
            android:layout_centerInParent="true"
            android:layout_alignParentLeft="true"
            android:textSize="12sp"/>

        <TextView
            android:id="@+id/submit"
            android:textSize="20sp"
            android:textColor="@color/colorWhite"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="5dp"
            android:layout_alignParentRight="true"
            android:layout_centerInParent="true"
            android:gravity="center_vertical"
            android:text="保存"/>
    </RelativeLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:padding="10dp">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="我的应用"
            android:textColor="#333333"
            android:textSize="16sp" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:text="(按住可拖动调整顺序)"
            android:textColor="#808080"
            android:textSize="13sp" />
    </LinearLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerViewExist"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingRight="10dp" />
    <View
        android:layout_width="match_parent"
        android:layout_height="4dp"
        android:background="@color/line_color">
    </View>

    <HorizontalScrollView
        android:id="@+id/horizonLScrollView"
        android:layout_width="match_parent"
        android:layout_height="35dp"
        android:scrollbarThumbHorizontal="@color/transparent"
        android:scrollbars="none">
        <RadioGroup
            android:id="@+id/rg_tab"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center_vertical"
            android:orientation="horizontal" />
    </HorizontalScrollView>

    <View
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:background="@color/line_color">
    </View>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerViewAll"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:paddingRight="10dp" />
</LinearLayout>

activity 代码:

package com.daobo.wand

import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import kotlinx.android.synthetic.main.activity_main.*
import android.view.View.OnClickListener
import androidx.recyclerview.widget.GridLayoutManager
import com.daobo.wand.ui.*
import android.widget.RadioButton
import android.util.TypedValue
import android.view.Gravity
import androidx.recyclerview.widget.RecyclerView
import android.app.Activity
import android.os.Build
import android.util.DisplayMetrics
import android.widget.Toast
import android.widget.CompoundButton
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import com.daobo.wand.ui.adapter.FunctionAdapter
import com.daobo.wand.ui.adapter.FunctionBlockAdapter
import com.daobo.wand.ui.listener.DefaultItemCallback
import com.daobo.wand.ui.listener.DefaultItemTouchHelper
import com.daobo.wand.ui.util.SFUtils


/**
 * 主菜单页面
 * @author xiaolong.li
 * @time 2020-02-14
 */
class MainActivity : AppCompatActivity(), OnClickListener {

    private var blockAdapter: FunctionBlockAdapter? = null
    private var functionAdapter: FunctionAdapter? = null
    private var gridManager: GridLayoutManager? = null

    private var scrollTab = ArrayList<String>()

    private var itemWidth = 0
    private var lastRow = 0
    private var isMove = false//滑动状态
    private var scrollPosition = 0
    private var currentTab: String? = null//当前的标签
    private var tabWidth = 0//标签宽度


    private var allData: ArrayList<FunctionItem>? = null
    private var selData: ArrayList<FunctionItem>? = null
    private var sfUtils: SFUtils? = null
    private val maxCount = 14
    private var isDrag = false

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

        submit.setOnClickListener(this)
    }

    private fun init () {
        sfUtils = SFUtils(this)
        allData = sfUtils!!.getAllFunctionItems() //sfUtils!!.getAllFunctionWithState()
        selData = sfUtils!!.getSelectFunctionItem()

        blockAdapter = FunctionBlockAdapter(this, selData!!)
        recyclerViewExist.layoutManager = GridLayoutManager(this, 4)
        recyclerViewExist.adapter = blockAdapter
        recyclerViewExist.addItemDecoration(SpaceItemDecoration(4, dip2px(this, 10.0F)))

        val callback = DefaultItemCallback(blockAdapter!!)
        val helper = DefaultItemTouchHelper(callback)
        helper.attachToRecyclerView(recyclerViewExist)

        gridManager = GridLayoutManager(this, 4)
        gridManager!!.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
            override fun getSpanSize(position: Int): Int {
                val fi = allData!![position]
                return if (fi.isTitle) 4 else 1
            }
        }
        functionAdapter = FunctionAdapter(this, allData!!)
        recyclerViewAll.layoutManager = gridManager
        recyclerViewAll.adapter = functionAdapter
        val spaceDecoration = SpaceItemDecoration(4, dip2px(this, 10.0F))
        recyclerViewAll.addItemDecoration(spaceDecoration)
        itemWidth = getAtyWidth(this) / 4 + dip2px(this, 2.0F)
        resetEditHeight(selData!!.size)
        initTab()
    }

    private fun initTab () {
        try {
            val tabs = sfUtils!!.getTabFunctionItems()
            if (tabs != null && tabs.isNotEmpty()) {
                currentTab = tabs[0].mName
                val padding = dip2px(this, 10.0F)
                val size = tabs.size
                for (i in 0 until size) {
                    val item = tabs[i]
                    if (item.isTitle) {
                        scrollTab.add(item.mName.toString())
                        val rb = RadioButton(this)
                        rb.setPadding(padding, 0, padding, 0)
                        rb.buttonDrawable = null
                        rb.gravity = Gravity.CENTER
                        rb.text = item.mName
                        rb.tag = item.subItemCount
                        rb.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14F)
                        try {
                            rb.setTextColor(ContextCompat.getColorStateList(this, R.color.colorGray))
                        } catch (e: Exception) {
                            e.printStackTrace()
                        }

                        rb.setCompoundDrawablesWithIntrinsicBounds(null, null, null,
                            ContextCompat.getDrawable(this, R.drawable.bg_block_tab))
                        rb.setOnCheckedChangeListener(onCheckedChangeListener)
                        rg_tab.addView(rb)
                    }
                }
                (rg_tab.getChildAt(0) as RadioButton).isChecked = true
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun resetEditHeight(size: Int) {
        var size = size
        try {
            if (size == 0) {
                size = 1
            }
            var row = size / 4 + if (size % 4 > 0) 1 else 0
            if (row <= 0)
                row = 1
            if (lastRow != row) {
                lastRow = row
                val params = recyclerViewExist.layoutParams
                params.height = itemWidth * row
                recyclerViewExist.layoutParams = params
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private val onCheckedChangeListener =
        CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
            try {
                val position = buttonView.tag as Int
                val text = buttonView.text.toString()
                if (currentTab != text && isChecked) {
                    currentTab = text
                    moveToPosition(position)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

    private fun moveToPosition(position: Int) {
        val first = gridManager!!.findFirstVisibleItemPosition()
        val end = gridManager!!.findLastVisibleItemPosition()
        if (first == -1 || end == -1)
            return
        if (position <= first) {      //移动到前面
            gridManager!!.scrollToPosition(position)
        } else if (position >= end) {      //移动到后面
            isMove = true
            scrollPosition = position
            gridManager!!.smoothScrollToPosition(recyclerViewAll, null, position)
        } else {//中间部分
            val n = position - gridManager!!.findFirstVisibleItemPosition()
            if (n > 0 && n < allData!!.size) {
                val top = gridManager!!.findViewByPosition(position)!!.top
                recyclerViewAll.scrollBy(0, top)
            }
        }
    }

    private val onScrollListener = object : RecyclerView.OnScrollListener() {
        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            super.onScrollStateChanged(recyclerView, newState)
            try {
                if (isMove && newState == RecyclerView.SCROLL_STATE_IDLE) {
                    isMove = false
                    val view = gridManager!!.findViewByPosition(scrollPosition)
                    if (view != null) {
                        val top = view.top
                        recyclerView.scrollBy(0, top)
                    }
                }
                isDrag = newState == RecyclerView.SCROLL_STATE_DRAGGING
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)
            if (isDrag) {  //拖动过程中
                val position = gridManager!!.findFirstVisibleItemPosition()
                if (position > 0) {
                    for (i in 0 until position + 1) {
                        if (allData!![i].isTitle) {
                            currentTab = allData!![i].mName
                        }
                    }
                    scrollTab(currentTab!!)
                }
            }
        }
    }

    private fun scrollTab(newTab: String) {
        try {
            val position = scrollTab.indexOf(currentTab)
            val targetPosition = scrollTab.indexOf(newTab)
            currentTab = newTab
            if (targetPosition != -1) {
                val x = (targetPosition - position) * getTabWidth()
                val radioButton = rg_tab.getChildAt(targetPosition) as RadioButton
                radioButton.setOnCheckedChangeListener(null)
                radioButton.isChecked = true
                radioButton.setOnCheckedChangeListener(onCheckedChangeListener)
                horizonLScrollView.scrollBy(x, 0)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }

    private fun getTabWidth(): Int {
        if (tabWidth == 0) {
            if (rg_tab != null && rg_tab.childCount !== 0) {
                tabWidth = rg_tab.width / rg_tab.childCount
            }
        }
        return tabWidth
    }

    private fun dip2px(context: Context, dpValue: Float): Int {
        val scale = context.resources.displayMetrics.density
        return (dpValue * scale + 0.5f).toInt()
    }

    private fun getAtyWidth(context: Context): Int {
        return try {
            val mDm = DisplayMetrics()
            (context as Activity).windowManager.defaultDisplay
                .getMetrics(mDm)
            mDm.widthPixels
        } catch (e: Exception) {
            0
        }
    }


    private fun addListener() {
        functionAdapter!!.setOnItemAddListener(object : FunctionAdapter.OnItemAddListener {
            override fun add(item: FunctionItem): Boolean {
                if (selData != null && selData!!.size < maxCount) {   // 更新选择列表,所有列表已在内部进行更新
                    try {
                        selData!!.add(item)
                        resetEditHeight(selData!!.size)
                        blockAdapter!!.notifyDataSetChanged()
                        item.mIsSelect = true
                        return true
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                    return false
                } else {
                    Toast.makeText(this@MainActivity, "选中的模块不能超过" + maxCount + "个",
                        Toast.LENGTH_SHORT).show()
                    return false
                }
            }
        })

        blockAdapter!!.setOnItemRemoveListener(object : FunctionBlockAdapter.OnItemRemoveListener {
            override fun remove(item: FunctionItem) {
                // 更新所有列表,选择列表已在内部进行更新
                try {
                    if (item?.mName != null) {
                        for (i in allData!!.indices) {
                            val data = allData!![i]
                            if (data?.mName != null) {
                                if (item.mName.equals(data.mName)) {
                                    data.mIsSelect = false
                                    break
                                }
                            }
                        }
                        functionAdapter!!.notifyDataSetChanged()
                    }
                    resetEditHeight(selData!!.size)
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        })
        recyclerViewAll.addOnScrollListener(onScrollListener)
    }


    override fun onClick(v: View?) {
        //TODO("not implemented")
        // To change body of created functions use File | Settings | File Templates.
        var intent = Intent()
        when(v?.id) {
            R.id.submit ->{
                //点击了
                sfUtils!!.saveSelectFunctionItem(selData!!)
                sfUtils!!.saveAllFunctionWithState(allData!!)
                Toast.makeText(this@MainActivity, "保存成功!",
                    Toast.LENGTH_SHORT).show()
            }
           
        }
    }


}

自定义控件代码:SquareRelativeLayout

package com.daobo.wand.ui
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.RelativeLayout
class SquareRelativeLayout : RelativeLayout {

    constructor (context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)

    constructor (context: Context, attrs: AttributeSet) : super(context, attrs)
    constructor (context: Context) : super(context)
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        var widthMeasureSpec = widthMeasureSpec
        var heightMeasureSpec = heightMeasureSpec
        setMeasuredDimension(
            View.getDefaultSize(0, widthMeasureSpec),
            View.getDefaultSize(0, heightMeasureSpec)
        )
        val childWidthSize = measuredWidth
        widthMeasureSpec =
            View.MeasureSpec.makeMeasureSpec(childWidthSize, View.MeasureSpec.EXACTLY)
        heightMeasureSpec = widthMeasureSpec
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }
}
SpaceItemDecoration类:
package com.daobo.wand.ui
import androidx.recyclerview.widget.RecyclerView
import android.graphics.Canvas
import android.graphics.Rect
import android.view.View
import androidx.recyclerview.widget.RecyclerView.ItemDecoration

class SpaceItemDecoration (row: Int, space: Int) : ItemDecoration() {

    private var mRow = row
    private val mSpace = space

    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
        outRect.left = mSpace
        outRect.bottom = mSpace
        //if (parent.getChildAdapterPosition(view) % row == 0)
        //outRect.left = 0
    }

    override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        super.onDrawOver(c, parent, state)
    }

}

bean 类:

package com.daobo.wand.ui

class TabItem(tabName : String, functionItems : ArrayList<FunctionItem>) {

    private var mTtabName = tabName
    private var mFunctionItems: ArrayList<FunctionItem>? = functionItems

    fun getTabName(): String {
        return mTtabName
    }

    fun setTabName(tabName: String) {
        this.mTtabName = tabName
    }

    fun getFunctionItems(): ArrayList<FunctionItem>? {
        return mFunctionItems
    }

    fun setFunctionItems(functionItems: ArrayList<FunctionItem>) {
        this.mFunctionItems = functionItems
    }
}
package com.daobo.wand.ui

class FunctionItem {

    var mName: String? = null
    var mIsSelect = false
    var mImageUrl = ""
    var mBackground = ""
    var isTitle = false
    var subItemCount = 0

    constructor(name: String, isSelect: Boolean, imageUrl: String, background: String) {
        this.mName = name
        this.mIsSelect = isSelect
        this.mImageUrl = imageUrl
        this.mBackground = background
    }

    constructor(name: String, isTitle: Boolean, subItemCount: Int) {
        this.mName = name
        this.isTitle = isTitle
        this.subItemCount = subItemCount
    }

    constructor(name: String, isTitle: Boolean) {
        this.mName = name
        this.isTitle = isTitle
    }
}
package com.daobo.wand.ui.viewbean


class FuncItemViewBean {

    var Name : String ? = ""

    var BtnImgSrc : Int = 0

    var IvImgSrc : Int = 0

}

 item 布局xml: layout_function_text

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="name" type="String"/>
    </data>
    <TextView
        android:id="@+id/func_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/bg_white"
        android:drawableLeft="@drawable/item_block_left"
        android:gravity="center_vertical"
        android:paddingBottom="4dp"
        android:paddingTop="4dp"
        android:textColor="@color/black"
        android:textSize="18sp"
        android:text="@{name}"/>
</layout>

layout_function_item

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="funcItem" type="com.daobo.wand.ui.viewbean.FuncItemViewBean"/>
    </data>
    <com.daobo.wand.ui.SquareRelativeLayout
        android:id="@+id/item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/bg_grid_press">

        <LinearLayout
            android:id="@+id/layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:gravity="center"
            android:orientation="vertical">

            <ImageView
                android:id="@+id/iv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@null"
                android:contentDescription="@string/app_name"
                android:scaleType="centerInside"
                android:src="@{funcItem.ivImgSrc}"/>

            <TextView
                android:id="@+id/text"
                android:layout_marginTop="2dp"
                android:lines="2"
                android:textSize="12sp"
                android:paddingLeft="5dp"
                android:paddingRight="5dp"
                android:gravity="center_horizontal"
                android:textColor="@color/black"
                android:layout_gravity="center_horizontal"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{funcItem.Name}"/>
        </LinearLayout>

        <ImageView
            android:id="@+id/btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:layout_marginRight="1dp"
            android:layout_marginTop="1dp"
            android:background="@null"
            android:contentDescription="@string/app_name"
            android:padding="4dp"
            android:scaleType="centerInside"
            android:src="@{funcItem.btnImgSrc}" />

   </com.daobo.wand.ui.SquareRelativeLayout>
</layout>

自定义 drawable xml
bg_block_tab:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/item_block_tab_checked" android:state_checked="true" />
    <item android:drawable="@drawable/item_block_tab_unchecked" android:state_checked="false" />
</selector>

bg_blue:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <solid android:color="@color/titlecolor" />
</shape>

bg_grid_press:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape>
            <solid android:color="#f5f5f5" />
        </shape>
    </item>
    <item android:state_pressed="false">
        <shape>
            <solid android:color="#f4f4f4" />
        </shape>
    </item>
</selector>

bg_white:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/colorWhite"/>
</shape>

适配器代码:

package com.daobo.wand.ui.adapter

import androidx.recyclerview.widget.RecyclerView
import com.daobo.wand.ui.FunctionItem
import android.content.Context
import android.view.ViewGroup
import android.view.LayoutInflater
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView.Adapter
import com.daobo.wand.BR
import com.daobo.wand.R
import com.daobo.wand.databinding.LayoutGridItemBinding
import com.daobo.wand.ui.viewbean.FuncItemViewBean

class FunctionAdapter : Adapter<RecyclerView.ViewHolder> {

    private var data = ArrayList<FunctionItem>()
    private val context: Context

    constructor(context: Context, data: ArrayList<FunctionItem>) {
        this.context = context
        if (data != null) {
            this.data = data
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return if (0 == viewType) {
            TitleViewHolder(DataBindingUtil.inflate(LayoutInflater.from(context),
                R.layout.layout_function_text, parent, false))
     
        } else {
            FunctionViewHolder(DataBindingUtil.inflate(LayoutInflater.from(context),
                R.layout.layout_grid_item, parent, false))
            
        }
    }

    override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
        if (0 == getItemViewType(position)) {
            var binding : ViewDataBinding = DataBindingUtil.getBinding(viewHolder.itemView)!!
            binding.setVariable(BR.name, data[position].mName)
            binding.executePendingBindings()
            //val holder = viewHolder as TitleViewHolder
            //holder.text.setText(data[position].mName)
        } else {
            var binding : ViewDataBinding = DataBindingUtil.getBinding(viewHolder.itemView)!!
            val fi = data[position]
            var funcItemViewBean = FuncItemViewBean()
            funcItemViewBean.BtnImgSrc = if (fi.mIsSelect) R.drawable.item_block_selected else R.drawable.item_block_add
            funcItemViewBean.IvImgSrc = context.resources.getIdentifier(fi.mImageUrl, "drawable",
                context.packageName)
            funcItemViewBean.Name = fi.mName
            binding.setVariable(BR.funcItem, funcItemViewBean)
            binding.executePendingBindings()
else R.drawable.ic_block_add)
            var layoutGridItemBinding = binding as LayoutGridItemBinding
            layoutGridItemBinding.btn.setOnClickListener {
                val f = data[position]
                if (!f.mIsSelect) {
                    if (listener != null) {
                        if (listener!!.add(f)) {
                            f.mIsSelect = true
                            notifyDataSetChanged()
                        }
                    }
                }
            }
        }
    }


    override fun getItemViewType(position: Int): Int {
        return if (data[position].isTitle) 0 else 1
    }

    override fun getItemCount(): Int {
        return data.size
    }

    inner class TitleViewHolder(dataBinding: ViewDataBinding) : RecyclerView.ViewHolder(dataBinding.root)

    inner class FunctionViewHolder(dataBinding: ViewDataBinding) : RecyclerView.ViewHolder(dataBinding.root)



    interface OnItemAddListener {
        fun add(item: FunctionItem): Boolean
    }

    private var listener: OnItemAddListener? = null

    fun setOnItemAddListener(listener: OnItemAddListener) {
        this.listener = listener
    }
}

 

package com.daobo.wand.ui.adapter

import androidx.recyclerview.widget.RecyclerView
import com.daobo.wand.ui.listener.ItemTouchHelperAdapter
import com.daobo.wand.ui.FunctionItem
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import com.daobo.wand.BR
import com.daobo.wand.R
import com.daobo.wand.databinding.LayoutGridItemBinding
import com.daobo.wand.ui.viewbean.FuncItemViewBean
import java.util.*
import kotlin.collections.ArrayList

class FunctionBlockAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>, ItemTouchHelperAdapter {

    private var data = ArrayList<FunctionItem>()
    private var context: Context? = null

    constructor(context: Context, data: ArrayList<FunctionItem>) {
        this.context = context
        if (data != null) {
            this.data = data
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return FunctionViewHolder(DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.layout_grid_item, parent, false))
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val fi = data[position]
        var funcItemViewBean = FuncItemViewBean()
        funcItemViewBean.BtnImgSrc = R.drawable.item_block_delete
        funcItemViewBean.IvImgSrc = context!!.resources.getIdentifier(fi.mImageUrl, "drawable",
            context!!.packageName)
        funcItemViewBean.Name = fi.mName
        var binding : ViewDataBinding = DataBindingUtil.getBinding(holder.itemView)!!
        binding.setVariable(BR.funcItem, funcItemViewBean)
        binding.executePendingBindings()
        var layoutGridItemBinding = binding as LayoutGridItemBinding
        layoutGridItemBinding.btn.setOnClickListener {
            val fi = data.removeAt(position)
            if (listener != null) {
                listener!!.remove(fi)
            }
            notifyDataSetChanged()
        }
    }

    override fun getItemCount(): Int {
        return data.size
    }

    override fun onItemMove(holder: RecyclerView.ViewHolder, fromPosition: Int, targetPosition: Int) {
        if (fromPosition < data.size && targetPosition < data.size) {
            Collections.swap(data, fromPosition, targetPosition)
            notifyItemMoved(fromPosition, targetPosition)
        }
    }

    override fun onItemSelect(holder: RecyclerView.ViewHolder) {
        holder.itemView.scaleX = 0.8f
        holder.itemView.scaleY = 0.8f
    }

    override fun onItemClear(holder: RecyclerView.ViewHolder) {
        holder.itemView.scaleX = 1.0f
        holder.itemView.scaleY = 1.0f
    }

    override fun onItemDismiss(holder: RecyclerView.ViewHolder) {
    }

    inner class FunctionViewHolder(dataBinding: ViewDataBinding) : RecyclerView.ViewHolder(dataBinding.root)


    interface OnItemRemoveListener {
        fun remove(item: FunctionItem)
    }

    private var listener: OnItemRemoveListener? = null

    fun setOnItemRemoveListener(listener: OnItemRemoveListener) {
        this.listener = listener
    }
}

listener包下面定义的监听:

package com.daobo.wand.ui.listener

import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView

class DefaultItemCallback : ItemTouchHelper.Callback {

    private var touchHelperAdapter: ItemTouchHelperAdapter

    constructor(touchHelperAdapter: ItemTouchHelperAdapter) {
        this.touchHelperAdapter = touchHelperAdapter
    }

    override fun getMovementFlags(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder
    ): Int {
        val dragFlags =
            ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT //允许上下左右的拖动
        return ItemTouchHelper.Callback.makeMovementFlags(dragFlags, 0)
    }

    override fun onMove(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder,
        target: RecyclerView.ViewHolder
    ): Boolean {
        touchHelperAdapter.onItemMove(
            viewHolder,
            viewHolder.adapterPosition,
            target.adapterPosition
        )
        return true
    }

    override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE)
            touchHelperAdapter.onItemSelect(viewHolder!!)
    }

    override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
        if (!recyclerView.isComputingLayout)
            touchHelperAdapter.onItemClear(viewHolder)
    }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {

    }

    override fun isLongPressDragEnabled(): Boolean {
        return true
    }

    override fun isItemViewSwipeEnabled(): Boolean {
        return false
    }
}
package com.daobo.wand.ui.listener

import androidx.recyclerview.widget.ItemTouchHelper

class DefaultItemTouchHelper : ItemTouchHelper {

    constructor(callback: ItemTouchHelper.Callback): super(callback)
}
package com.daobo.wand.ui.listener

import androidx.recyclerview.widget.RecyclerView

interface ItemTouchHelperAdapter {

    fun onItemMove(holder: RecyclerView.ViewHolder, fromPosition: Int, targetPosition: Int)

    fun onItemSelect(holder: RecyclerView.ViewHolder)

    fun onItemClear(holder: RecyclerView.ViewHolder)

    fun onItemDismiss(holder: RecyclerView.ViewHolder)
}

 注意:在layout_function_item binding imageview 的src 资源,我们需要定义下:

package com.daobo.wand.ui.util

import android.os.Build
import android.view.View
import android.widget.ImageView
import androidx.annotation.RequiresApi
import androidx.core.content.res.ResourcesCompat
import androidx.databinding.BindingAdapter

class ImageBindingUtil {

    companion object {

        @BindingAdapter("android:src")
        @JvmStatic
        fun setSrc(view: ImageView, resId: Int) {
            view.setImageResource(resId)
        }

        @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
        @JvmStatic
        @BindingAdapter("background")
        fun setBackground(view: View, id: Int) {
            //view.resources.getDrawable(id)
            view.background = ResourcesCompat.getDrawable(view.resources, id, null)
        }
    }
}

binding adapter方法只需要全局static 声明下,但是要使用注解@JvmStatic

工具类 用户来初始化数据,且将数据保存到preferences中:

package com.daobo.wand.ui.util

import android.content.Context
import android.content.SharedPreferences
import com.daobo.wand.ui.FunctionItem
import com.daobo.wand.ui.TabItem
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader

class SFUtils {

    private var context: Context? = null
    private var sp: SharedPreferences? = null

    var tabItems : ArrayList<TabItem> =  ArrayList()

    constructor(context: Context) {
        this.context = context
        sp = context.getSharedPreferences("menudata", Context.MODE_PRIVATE)
        initData()
    }

    /**
     * 把已有的菜单数据 配置到
     * assets menuData 配置文件中
     */
    fun getAllFunctionWithState(): ArrayList<FunctionItem> {
        var allData = sp!!.getString("allData", "")
        var functionItems = ArrayList<FunctionItem>()
        var tabItems: List<TabItem>? = null
        if ("" == allData) {
            try {
                val ins = context!!.assets.open("menuData.txt")
                val isr = InputStreamReader(ins)
                val br = BufferedReader(isr)
                var str: String? = br.readLine()
                val sbuf = StringBuffer()
                while (str != null) {
                    sbuf.append(str)
                }
                br.close()
                isr.close()
                ins.close()
                allData = sbuf.toString()
                tabItems = Gson().fromJson(allData, object : TypeToken<List<TabItem>>(){}.type)
                if (tabItems != null) {
                    for (i in tabItems!!.indices) {
                        val functionItem = FunctionItem(tabItems[i].getTabName(), true)
                        functionItems.add(functionItem)
                        functionItems.addAll(tabItems[i].getFunctionItems()!!)
                    }
                }
            } catch (e: IOException) {
                e.printStackTrace()
            }
        } else {
            functionItems = Gson().fromJson(allData, object : TypeToken<List<FunctionItem>>(){}.type)
        }
        return functionItems
    }

    /**
     * 把用户的选择 保存到Preferences 文件
     * 即使 app 推出运行,内存数据清理掉
     * */
    fun getSelectFunctionItem(): ArrayList<FunctionItem> {
        val selData = sp!!.getString("selData", "")
        var functionItems: ArrayList<FunctionItem>? = null
        functionItems = if ("" == selData) {
            ArrayList()
        } else {
            Gson().fromJson(selData, object : TypeToken<List<FunctionItem>>(){}.type)
        }
        return functionItems!!
    }

    fun getAllFunctionItems () : ArrayList<FunctionItem>{
        var functionItems = ArrayList<FunctionItem>()
        for (i in tabItems!!.indices) {
            val functionItem = FunctionItem(tabItems[i].getTabName(), true)
            functionItems.add(functionItem)
            functionItems.addAll(tabItems[i].getFunctionItems()!!)
        }
        return functionItems
    }

    fun getTabFunctionItems(): ArrayList<FunctionItem> {
        var tabItemsCount = 0 //用于标记之后滑动的位置
        var functionItems = ArrayList<FunctionItem>()
        for (i in tabItems!!.indices) {
            val functionItem =
                FunctionItem(tabItems[i].getTabName(), true, tabItemsCount)
            tabItemsCount += tabItems[i].getFunctionItems()!!.size + 1
            functionItems.add(functionItem)
        }
        return functionItems
    }


    fun getTabNames(): ArrayList<FunctionItem> {
        var allData = sp!!.getString("allData", "")
        var functionItems = ArrayList<FunctionItem>()
        var tabItems: List<TabItem>? = null
        if ("" == allData) {
            try {
                val ins = context!!.assets.open("menuData.txt")
                val isr = InputStreamReader(ins)
                val br = BufferedReader(isr)
                var str: String? = br.readLine()
                val sbuf = StringBuffer()
                while (str != null) {
                    sbuf.append(str)
                }
                br.close()
                isr.close()
                ins.close()
                allData = sbuf.toString()
                tabItems = Gson().fromJson(allData, object : TypeToken<List<TabItem>>(){}.type)
                if (tabItems != null) {
                    var tabItemsCount = 0 //用于标记之后滑动的位置
                    for (i in tabItems!!.indices) {
                        val functionItem =
                            FunctionItem(tabItems[i].getTabName(), true, tabItemsCount)
                        tabItemsCount += tabItems[i].getFunctionItems()!!.size + 1
                        functionItems.add(functionItem)
                    }
                }
            } catch (e: IOException) { e.printStackTrace() }
        }
        //else{
        //    functionItems =  Gson().fromJson(allData, object : TypeToken<List<FunctionItem>>(){}.type)
       // }
        return functionItems
    }

    fun saveSelectFunctionItem(selData: List<FunctionItem>) {
        sp!!.edit().putString("selData", Gson().toJson(selData)).apply()
    }

    fun saveAllFunctionWithState(allData: List<FunctionItem>) {
        sp!!.edit().putString("allData", Gson().toJson(allData)).apply()
    }

    private fun initData () {
        var arrayList : ArrayList<FunctionItem> =  ArrayList()
        arrayList.add(FunctionItem("充值中心",false,"icon_home_selected","#86c751"))
        arrayList.add(FunctionItem("信用卡还款",false,"icon_home_selected","#86c751"))
        arrayList.add(FunctionItem("生活缴费",false,"icon_home_selected","#86c751"))
        arrayList.add(FunctionItem("城市服务",false,"icon_home_selected","#86c751"))
        arrayList.add(FunctionItem("生活号",false,"icon_home_selected","#86c751"))
        arrayList.add(FunctionItem("我的客服",false,"icon_home_selected","#86c751"))
        arrayList.add(FunctionItem("我的快递",false,"icon_home_selected","#86c751"))
        arrayList.add(FunctionItem("医疗健康",false,"icon_home_selected","#86c751"))
        arrayList.add( FunctionItem("记账本",false,"icon_home_selected","#86c751"))
        arrayList.add(FunctionItem("城市一卡通",false,"icon_home_selected","#86c751"))
        arrayList.add(FunctionItem("发票管家",false,"icon_home_selected","#86c751"))
        arrayList.add(FunctionItem("蚂蚁宝卡",false,"icon_home_selected","#86c751"))
        arrayList.add(FunctionItem("车主服务",false,"icon_home_selected","#86c751"))
        arrayList.add( FunctionItem("天天有料",false,"icon_home_selected","#86c751"))
        var tabItem : TabItem = TabItem("便民生活", arrayList)
        tabItems.add(tabItem)

        var arrayList1 : ArrayList<FunctionItem> = ArrayList()
        arrayList1.add(FunctionItem("余额宝",false,"icon_home_selected","#86c751"))
        arrayList1.add(FunctionItem("花呗",false,"icon_home_selected","#86c751"))
        arrayList1.add(FunctionItem("芝麻信用",false,"icon_home_selected","#86c751"))
        arrayList1.add(FunctionItem("蚂蚁借呗",false,"icon_home_selected","#86c751"))
        arrayList1.add(FunctionItem("股票",false,"icon_home_selected","#86c751"))
        arrayList1.add(FunctionItem("保险服务",false,"icon_home_selected","#86c751"))
        arrayList1.add(FunctionItem("汇率换算",false,"icon_home_selected","#86c751"))
        arrayList1.add(FunctionItem("理财小工具",false,"icon_home_selected","#86c751"))

        var tabItem1 : TabItem  = TabItem("财务管理",arrayList1)
        tabItems.add(tabItem1)

        var arrayList2 : ArrayList<FunctionItem> = ArrayList()
        arrayList2.add(FunctionItem("转账",false,"icon_home_selected","#86c751"))
        arrayList2.add(FunctionItem("红包",false,"icon_home_selected","#86c751"))
        arrayList2.add(FunctionItem("AA收款",false,"icon_home_selected","#86c751"))
        arrayList2.add(FunctionItem("亲密付",false,"icon_home_selected","#86c751"))
        arrayList2.add(FunctionItem("上银汇款",false,"icon_home_selected","#86c751"))
        arrayList2.add(FunctionItem("话费卡转让",false,"icon_home_selected","#86c751"))
        var tabItem2 : TabItem  = TabItem("资金往来",arrayList2)
        tabItems.add(tabItem2)

        var arrayList3 : ArrayList<FunctionItem> =  ArrayList()
        arrayList3.add(FunctionItem("游戏中心",false,"icon_home_selected","#86c751"))
        arrayList3.add(FunctionItem("出境",false,"icon_home_selected","#86c751"))
        arrayList3.add(FunctionItem("彩票",false,"icon_home_selected","#86c751"))
        arrayList3.add(FunctionItem("人脸识别",false,"icon_home_selected","#86c751"))
        arrayList3.add(FunctionItem("奖励金",false,"icon_home_selected","#86c751"))
        arrayList3.add(FunctionItem("世界杯",false,"icon_home_selected","#86c751"))
        var tabItem3 : TabItem  = TabItem("购物娱乐",arrayList3)
        tabItems.add(tabItem3)

        var arrayList4 : ArrayList<FunctionItem> = ArrayList()
        arrayList4.add(FunctionItem("大学生活",false,"icon_home_selected","#86c751"))
        arrayList4.add(FunctionItem("爱心捐赠",false,"icon_home_selected","#86c751"))
        arrayList4.add(FunctionItem("蚂蚁森林",false,"icon_home_selected","#86c751"))
        arrayList4.add(FunctionItem("蚂蚁庄园",false,"icon_home_selected","#86c751"))
        arrayList4.add(FunctionItem("中小学",false,"icon_home_selected","#86c751"))
        arrayList4.add(FunctionItem("运动",false,"icon_home_selected","#86c751"))
        var tabItem4 : TabItem = TabItem("教育公益",arrayList4)
        tabItems.add(tabItem4)

        var arrayList5 : ArrayList<FunctionItem> =  ArrayList()
        arrayList5.add(FunctionItem("淘票票",false,"icon_home_selected","#86c751"))
        arrayList5.add(FunctionItem("滴滴出行",false,"icon_home_selected","#86c751"))
        arrayList5.add(FunctionItem("饿了么外卖",false,"icon_home_selected","#86c751"))
        arrayList5.add(FunctionItem("天猫",false,"icon_home_selected","#86c751"))
        arrayList5.add(FunctionItem("淘宝",false,"icon_home_selected","#86c751"))
        arrayList5.add(FunctionItem("火车票机票",false,"icon_home_selected","#86c751"))
        var tabItem5 : TabItem  = TabItem("第三方服务",arrayList5)
        tabItems.add(tabItem5)
    }
}

要使用我的图片资源,下载链接
                                                 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值