From 6284dbb083681f8fa14c32b76520d96493c0b627 Mon Sep 17 00:00:00 2001 From: zhangmengxiong Date: Wed, 29 Mar 2023 17:38:37 +0800 Subject: [PATCH 1/2] 666 --- .../java/com/mx/adapt/MXBaseSimpleAdapt.kt | 8 +- .../java/com/mx/adapt/scroller/IMXSelect.kt | 5 + .../com/mx/adapt/scroller/MXScrollerAdapt.kt | 66 ++++++++ .../com/mx/adapt/scroller/MXScrollerView.kt | 142 ++++++++++++++++++ .../res/layout/layout_mx_scroller_space.xml | 6 + app/src/main/AndroidManifest.xml | 1 + .../java/com/mx/recycle_adapt/MainActivity.kt | 2 + .../activity/ScrollerViewActivity.kt | 54 +++++++ .../res/layout/activity_scroller_view.xml | 20 +++ .../main/res/layout/adapt_simple_index.xml | 2 +- local.properties | 4 +- 11 files changed, 306 insertions(+), 4 deletions(-) create mode 100644 MXAdapt/src/main/java/com/mx/adapt/scroller/IMXSelect.kt create mode 100644 MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerAdapt.kt create mode 100644 MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerView.kt create mode 100644 MXAdapt/src/main/res/layout/layout_mx_scroller_space.xml create mode 100644 app/src/main/java/com/mx/recycle_adapt/activity/ScrollerViewActivity.kt create mode 100644 app/src/main/res/layout/activity_scroller_view.xml diff --git a/MXAdapt/src/main/java/com/mx/adapt/MXBaseSimpleAdapt.kt b/MXAdapt/src/main/java/com/mx/adapt/MXBaseSimpleAdapt.kt index 9db1812..2cceddc 100644 --- a/MXAdapt/src/main/java/com/mx/adapt/MXBaseSimpleAdapt.kt +++ b/MXAdapt/src/main/java/com/mx/adapt/MXBaseSimpleAdapt.kt @@ -53,6 +53,11 @@ abstract class MXBaseSimpleAdapt(val list: ArrayList = arrayListOf()) : } catch (e: Exception) { e.printStackTrace() } + try { + bindView(position, holder.binding) + } catch (e: Exception) { + e.printStackTrace() + } } /** @@ -77,7 +82,8 @@ abstract class MXBaseSimpleAdapt(val list: ArrayList = arrayListOf()) : * 绑定View * @param position 绑定View的位置 */ - abstract fun bindView(position: Int, binding: ViewBinding, record: T) + open fun bindView(position: Int, binding: ViewBinding, record: T) {} + open fun bindView(position: Int, binding: ViewBinding) {} /** * Item点击回调 diff --git a/MXAdapt/src/main/java/com/mx/adapt/scroller/IMXSelect.kt b/MXAdapt/src/main/java/com/mx/adapt/scroller/IMXSelect.kt new file mode 100644 index 0000000..3d1f14b --- /dev/null +++ b/MXAdapt/src/main/java/com/mx/adapt/scroller/IMXSelect.kt @@ -0,0 +1,5 @@ +package com.mx.adapt.scroller + +interface IMXSelect { + fun onSelect(index: Int) +} \ No newline at end of file diff --git a/MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerAdapt.kt b/MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerAdapt.kt new file mode 100644 index 0000000..31eff84 --- /dev/null +++ b/MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerAdapt.kt @@ -0,0 +1,66 @@ +package com.mx.adapt.scroller + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import androidx.viewbinding.ViewBinding +import com.mx.adapt.MXBaseSimpleAdapt +import com.mx.adapt.MXBaseViewHolder +import com.mx.adapt.databinding.LayoutMxScrollerSpaceBinding + +class MXScrollerAdapt(val scrollView: MXScrollerView) : MXBaseSimpleAdapt() { + var adapt: MXBaseSimpleAdapt<*>? = null + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MXBaseViewHolder { + if (viewType != Int.MAX_VALUE / 2) { + adapt?.onCreateViewHolder(parent, viewType)?.let { + return it + } + } + return MXBaseViewHolder( + LayoutMxScrollerSpaceBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ), viewType + ) + } + + override fun createItem( + inflater: LayoutInflater, + parent: ViewGroup, + viewType: Int + ): ViewBinding { + if (viewType != Int.MAX_VALUE / 2) { + adapt?.createItem(inflater, parent, viewType)?.let { + return it + } + } + return LayoutMxScrollerSpaceBinding.inflate(inflater, parent, false) + } + + override fun onBindViewHolder(holder: MXBaseViewHolder, position: Int) { + if (position >= scrollView.itemOffset && position < (itemCount - scrollView.itemOffset)) { + adapt?.onBindViewHolder(holder, position - scrollView.itemOffset) + } + val lp = (holder.binding.root.layoutParams as RecyclerView.LayoutParams) + lp.height = scrollView.itemHeight + holder.binding.root.layoutParams = lp + holder.itemView.setOnClickListener { + itemClickCall?.invoke(position, Any()) + } + } + + override fun getItemViewType(position: Int): Int { + val maxCount = itemCount + if (position < scrollView.itemOffset || position > (maxCount - scrollView.itemOffset)) { + return Int.MAX_VALUE / 2 + } + + return super.getItemViewType(position) + } + + override fun getItemCount(): Int { + return (adapt?.itemCount ?: 0) + scrollView.itemOffset * 2 + } +} \ No newline at end of file diff --git a/MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerView.kt b/MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerView.kt new file mode 100644 index 0000000..6e968cc --- /dev/null +++ b/MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerView.kt @@ -0,0 +1,142 @@ +package com.mx.adapt.scroller + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.RectF +import android.util.AttributeSet +import android.view.ViewTreeObserver +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.LinearSnapHelper +import androidx.recyclerview.widget.RecyclerView +import com.mx.adapt.MXBaseSimpleAdapt +import kotlin.math.max + +class MXScrollerView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null +) : RecyclerView(context, attrs) { + private val manager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) + private var dashColor: Int? = Color.parseColor("#33999999") + private var itemSize = 5 + internal val itemOffset: Int + get() = (itemSize - 1) / 2 + internal val itemHeight get() = getAllHeight() / itemSize + + + private var itemSelect: IMXSelect? = null + private val delegateAdapt = MXScrollerAdapt(this) + + init { + LinearSnapHelper().attachToRecyclerView(this) + layoutManager = manager + adapter = delegateAdapt + delegateAdapt.setItemClick { position, _ -> + manager.scrollToPositionWithOffset(position - itemOffset, 0) + notifySelectChange(position - itemOffset) + } + addOnScrollListener(object : OnScrollListener() { + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + if (newState == SCROLL_STATE_IDLE) { + notifySelectChange(manager.findFirstCompletelyVisibleItemPosition()) + } + } + + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + notifySelectChange(manager.findFirstCompletelyVisibleItemPosition()) + } + }) + + viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener { + override fun onPreDraw(): Boolean { + delegateAdapt?.notifyDataSetChanged() + viewTreeObserver.removeOnPreDrawListener(this) + return true + } + }) + } + + override fun onDraw(c: Canvas?) { + super.onDraw(c) + dashColor?.let { dash -> + val itemHeight = itemHeight + val itemOffset = itemOffset + c?.drawRect( + RectF( + 0f, + itemHeight * itemOffset.toFloat(), + width.toFloat(), + itemHeight * (itemOffset + 1).toFloat() + ), + Paint().apply { + color = dash + style = Paint.Style.FILL + }) + } + } + + private fun getAllHeight() = height - paddingTop - paddingBottom + + fun setDashColor(color: Int) { + dashColor = color + postInvalidate() + } + + fun setItemSize(size: Int) { + if (size % 2 == 0) { + throw Exception("数量不能为双数!") + } + itemSize = size + delegateAdapt.notifyDataSetChanged() + } + + fun setAdapt(adapt: MXBaseSimpleAdapt<*>) { + adapt.registerAdapterDataObserver(TypeObserver()) + delegateAdapt.adapt = adapt + } + + fun setSelectIndex(index: Int) { + val position = max(0, index) + manager.scrollToPositionWithOffset(position, position) + post { manager.scrollToPositionWithOffset(position, position) } + } + + fun setOnSelectListener(listener: IMXSelect?) { + itemSelect = listener + notifySelectChange(manager.findFirstCompletelyVisibleItemPosition() - itemOffset) + } + + private inner class TypeObserver : AdapterDataObserver() { + override fun onChanged() { + delegateAdapt.notifyDataSetChanged() + } + + override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { + delegateAdapt.notifyItemRangeInserted(positionStart + itemOffset, itemCount) + } + + override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) { + delegateAdapt.notifyItemRangeRemoved(positionStart + itemOffset, itemCount) + } + + override fun onItemRangeChanged(positionStart: Int, itemCount: Int) { + delegateAdapt.notifyItemRangeChanged(positionStart + itemOffset, itemCount) + } + + override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) { + delegateAdapt.notifyItemRangeChanged(positionStart + itemOffset, itemCount, payload) + } + + override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) { + delegateAdapt.notifyItemMoved(fromPosition + itemOffset, toPosition + itemOffset) + } + } + + private var currentSelectIndex = -1 + private fun notifySelectChange(index: Int) { + val index = if (index < 0) 0 else index + if (index == currentSelectIndex) return + currentSelectIndex = index + itemSelect?.onSelect(index) + } +} \ No newline at end of file diff --git a/MXAdapt/src/main/res/layout/layout_mx_scroller_space.xml b/MXAdapt/src/main/res/layout/layout_mx_scroller_space.xml new file mode 100644 index 0000000..64dd827 --- /dev/null +++ b/MXAdapt/src/main/res/layout/layout_mx_scroller_space.xml @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 45e9695..16cc61b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + diff --git a/app/src/main/java/com/mx/recycle_adapt/MainActivity.kt b/app/src/main/java/com/mx/recycle_adapt/MainActivity.kt index fa816a3..d0d5e64 100644 --- a/app/src/main/java/com/mx/recycle_adapt/MainActivity.kt +++ b/app/src/main/java/com/mx/recycle_adapt/MainActivity.kt @@ -7,6 +7,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.mx.recycle_adapt.activity.AnyTypeActivity import com.mx.recycle_adapt.activity.BannerActivity import com.mx.recycle_adapt.activity.IndexedActivity +import com.mx.recycle_adapt.activity.ScrollerViewActivity import com.mx.recycle_adapt.adapt.HomeAdapt import kotlinx.android.synthetic.main.activity_main.* @@ -19,6 +20,7 @@ class MainActivity : AppCompatActivity() { val adapt = HomeAdapt( arrayListOf( HomePages("普通的一个RecycleView", IndexedActivity::class.java), + HomePages("滚动选择View", ScrollerViewActivity::class.java), HomePages("多类型RecycleView", AnyTypeActivity::class.java), HomePages("Banner", BannerActivity::class.java), ) diff --git a/app/src/main/java/com/mx/recycle_adapt/activity/ScrollerViewActivity.kt b/app/src/main/java/com/mx/recycle_adapt/activity/ScrollerViewActivity.kt new file mode 100644 index 0000000..8fe1bea --- /dev/null +++ b/app/src/main/java/com/mx/recycle_adapt/activity/ScrollerViewActivity.kt @@ -0,0 +1,54 @@ +package com.mx.recycle_adapt.activity + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.viewbinding.ViewBinding +import com.mx.adapt.MXBaseSimpleAdapt +import com.mx.adapt.scroller.IMXSelect +import com.mx.recycle_adapt.R +import com.mx.recycle_adapt.databinding.AdaptSimpleIndexBinding +import kotlinx.android.synthetic.main.activity_scroller_view.* + +class ScrollerViewActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_scroller_view) + val adapt = SpanCountAdapt() + adapt.list.addAll((0 until 1000000)) + adapt.notifyDataSetChanged() + + scrollerView.setItemSize(5) + scrollerView.setAdapt(adapt) + scrollerView.setOnSelectListener(object : IMXSelect { + override fun onSelect(index: Int) { + infoTxv.text = index.toString() + } + }) + scrollerView.setSelectIndex(10) + } + + + private class SpanCountAdapt : MXBaseSimpleAdapt() { + init { + setItemClick { position, record -> + list.removeAt(position) + notifyItemRemoved(position) + } + } + + override fun createItem( + inflater: LayoutInflater, + parent: ViewGroup, + viewType: Int + ): AdaptSimpleIndexBinding { + return AdaptSimpleIndexBinding.inflate(inflater, parent, false) + } + + override fun bindView(position: Int, binding: ViewBinding, record: Int) { + binding as AdaptSimpleIndexBinding + binding.indexTxv.text = "" + (record + 1) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_scroller_view.xml b/app/src/main/res/layout/activity_scroller_view.xml new file mode 100644 index 0000000..f0226fb --- /dev/null +++ b/app/src/main/res/layout/activity_scroller_view.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/adapt_simple_index.xml b/app/src/main/res/layout/adapt_simple_index.xml index cd18494..bf39d6d 100644 --- a/app/src/main/res/layout/adapt_simple_index.xml +++ b/app/src/main/res/layout/adapt_simple_index.xml @@ -7,8 +7,8 @@ android:id="@+id/indexTxv" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_gravity="center" android:gravity="center" - android:padding="20dp" android:text="1" android:textColor="#000000" android:textSize="16sp" /> diff --git a/local.properties b/local.properties index 76366c1..ccc0961 100644 --- a/local.properties +++ b/local.properties @@ -4,5 +4,5 @@ # Location of the SDK. This is only used by Gradle. # For customization when using a Version Control System, please read the # header note. -#Mon Mar 13 19:28:20 CST 2023 -sdk.dir=D\:\\DevTools\\AndroidSDK +#Wed Mar 29 16:24:36 CST 2023 +sdk.dir=D\:\\DevTools\\WinAndroidSdk -- Gitee From a765560bba4802a5132d844b7f959669d01bef2a Mon Sep 17 00:00:00 2001 From: zhangmengxiong Date: Wed, 29 Mar 2023 17:45:09 +0800 Subject: [PATCH 2/2] 666 --- .../java/com/mx/adapt/scroller/MXScrollerAdapt.kt | 2 +- .../java/com/mx/adapt/scroller/MXScrollerView.kt | 9 +++++---- .../recycle_adapt/activity/ScrollerViewActivity.kt | 12 +++++++++++- app/src/main/res/layout/activity_scroller_view.xml | 10 ++++++++++ 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerAdapt.kt b/MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerAdapt.kt index 31eff84..2303b95 100644 --- a/MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerAdapt.kt +++ b/MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerAdapt.kt @@ -53,7 +53,7 @@ class MXScrollerAdapt(val scrollView: MXScrollerView) : MXBaseSimpleAdapt() override fun getItemViewType(position: Int): Int { val maxCount = itemCount - if (position < scrollView.itemOffset || position > (maxCount - scrollView.itemOffset)) { + if (position < scrollView.itemOffset || position >= (maxCount - scrollView.itemOffset)) { return Int.MAX_VALUE / 2 } diff --git a/MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerView.kt b/MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerView.kt index 6e968cc..9710b8c 100644 --- a/MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerView.kt +++ b/MXAdapt/src/main/java/com/mx/adapt/scroller/MXScrollerView.kt @@ -99,6 +99,7 @@ class MXScrollerView @JvmOverloads constructor( val position = max(0, index) manager.scrollToPositionWithOffset(position, position) post { manager.scrollToPositionWithOffset(position, position) } + notifySelectChange(position) } fun setOnSelectListener(listener: IMXSelect?) { @@ -134,9 +135,9 @@ class MXScrollerView @JvmOverloads constructor( private var currentSelectIndex = -1 private fun notifySelectChange(index: Int) { - val index = if (index < 0) 0 else index - if (index == currentSelectIndex) return - currentSelectIndex = index - itemSelect?.onSelect(index) + val targetIndex = if (index < 0) 0 else index + if (targetIndex == currentSelectIndex) return + currentSelectIndex = targetIndex + itemSelect?.onSelect(targetIndex) } } \ No newline at end of file diff --git a/app/src/main/java/com/mx/recycle_adapt/activity/ScrollerViewActivity.kt b/app/src/main/java/com/mx/recycle_adapt/activity/ScrollerViewActivity.kt index 8fe1bea..79ccf02 100644 --- a/app/src/main/java/com/mx/recycle_adapt/activity/ScrollerViewActivity.kt +++ b/app/src/main/java/com/mx/recycle_adapt/activity/ScrollerViewActivity.kt @@ -1,5 +1,6 @@ package com.mx.recycle_adapt.activity +import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater import android.view.ViewGroup @@ -16,17 +17,26 @@ class ScrollerViewActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_scroller_view) val adapt = SpanCountAdapt() - adapt.list.addAll((0 until 1000000)) + adapt.list.addAll((0 until 13)) adapt.notifyDataSetChanged() scrollerView.setItemSize(5) scrollerView.setAdapt(adapt) + + var currentIndex = 0 scrollerView.setOnSelectListener(object : IMXSelect { override fun onSelect(index: Int) { infoTxv.text = index.toString() + currentIndex = index } }) scrollerView.setSelectIndex(10) + scrollerView.setDashColor(Color.parseColor("#33465FCD")) + + addTxv.setOnClickListener { + adapt.list.add(currentIndex, currentIndex) + adapt.notifyDataSetChanged() + } } diff --git a/app/src/main/res/layout/activity_scroller_view.xml b/app/src/main/res/layout/activity_scroller_view.xml index f0226fb..29a6a57 100644 --- a/app/src/main/res/layout/activity_scroller_view.xml +++ b/app/src/main/res/layout/activity_scroller_view.xml @@ -13,6 +13,16 @@ android:textColor="#000000" android:textSize="14sp" /> + +