From 27b9b13579974912096f2ae6d59061f58e17c7a3 Mon Sep 17 00:00:00 2001 From: ChanNagihong Date: Wed, 28 Jul 2021 15:46:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=20SnapColumns=20=E7=89=B9?= =?UTF-8?q?=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 1 + .../tableview/demo/lesson9/Lesson9Activity.kt | 31 +++++++ .../demo/lesson9/Lesson9ViewColumn.kt | 15 ++++ .../demo/lesson9/Lesson9ViewModel.kt | 68 +++++++++++++++ .../tableview/demo/main/MainActivity.kt | 5 ++ app/src/main/res/layout/activity_lesson_9.xml | 9 ++ app/src/main/res/layout/activity_main.xml | 14 ++- .../layout/layout_lesson_9_view_column.xml | 30 +++++++ gradle/wrapper/gradle-wrapper.properties | 2 +- .../java/cn/jingzhuan/tableview/TableView.kt | 31 +++++-- .../jingzhuan/tableview/element/HeaderRow.kt | 13 ++- .../cn/jingzhuan/tableview/element/Row.kt | 19 ++-- .../layoutmanager/ColumnsLayoutManager.kt | 86 ++++++++++++++++++- .../layoutmanager/RowListLayoutManager.kt | 24 +++++- .../tableview/layoutmanager/TableSpecs.kt | 51 ++++++++++- updateLibsAndRun | 5 +- 16 files changed, 368 insertions(+), 36 deletions(-) create mode 100644 app/src/main/java/cn/jingzhuan/tableview/demo/lesson9/Lesson9Activity.kt create mode 100644 app/src/main/java/cn/jingzhuan/tableview/demo/lesson9/Lesson9ViewColumn.kt create mode 100644 app/src/main/java/cn/jingzhuan/tableview/demo/lesson9/Lesson9ViewModel.kt create mode 100644 app/src/main/res/layout/activity_lesson_9.xml create mode 100644 app/src/main/res/layout/layout_lesson_9_view_column.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bdeb09e..edbe40e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -28,6 +28,7 @@ + \ No newline at end of file diff --git a/app/src/main/java/cn/jingzhuan/tableview/demo/lesson9/Lesson9Activity.kt b/app/src/main/java/cn/jingzhuan/tableview/demo/lesson9/Lesson9Activity.kt new file mode 100644 index 0000000..fb3a3ac --- /dev/null +++ b/app/src/main/java/cn/jingzhuan/tableview/demo/lesson9/Lesson9Activity.kt @@ -0,0 +1,31 @@ +package cn.jingzhuan.tableview.demo.lesson9 + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.ViewModelProviders +import cn.jingzhuan.tableview.demo.R +import cn.jingzhuan.tableview.demo.databinding.ActivityLesson9Binding + +class Lesson9Activity : AppCompatActivity() { + + private lateinit var binding: ActivityLesson9Binding + private lateinit var viewModel: Lesson9ViewModel + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + title = "Lesson 9" + binding = DataBindingUtil.setContentView(this, R.layout.activity_lesson_9) + viewModel = ViewModelProviders.of(this)[Lesson9ViewModel::class.java] + + binding.tableView.updateTableSize(15, 1, 3) + + viewModel.liveData.observe(this) { + binding.tableView.setHeaderRow(it) + binding.tableView.notifyDataSetChanged() + } + + viewModel.fetch(this, 100, 15) + } + +} \ No newline at end of file diff --git a/app/src/main/java/cn/jingzhuan/tableview/demo/lesson9/Lesson9ViewColumn.kt b/app/src/main/java/cn/jingzhuan/tableview/demo/lesson9/Lesson9ViewColumn.kt new file mode 100644 index 0000000..1de886c --- /dev/null +++ b/app/src/main/java/cn/jingzhuan/tableview/demo/lesson9/Lesson9ViewColumn.kt @@ -0,0 +1,15 @@ +package cn.jingzhuan.tableview.demo.lesson9 + +import cn.jingzhuan.tableview.demo.R +import cn.jingzhuan.tableview.demo.databinding.LayoutLesson9ViewColumnBinding +import cn.jingzhuan.tableview.element.DataBindingViewColumn +import cn.jingzhuan.tableview.element.Row + +class Lesson9ViewColumn: DataBindingViewColumn() { + + override fun layoutId() = R.layout.layout_lesson_9_view_column + + override fun onBind(binding: LayoutLesson9ViewColumnBinding, row: Row<*>) { + + } +} \ No newline at end of file diff --git a/app/src/main/java/cn/jingzhuan/tableview/demo/lesson9/Lesson9ViewModel.kt b/app/src/main/java/cn/jingzhuan/tableview/demo/lesson9/Lesson9ViewModel.kt new file mode 100644 index 0000000..fe9fdd1 --- /dev/null +++ b/app/src/main/java/cn/jingzhuan/tableview/demo/lesson9/Lesson9ViewModel.kt @@ -0,0 +1,68 @@ +package cn.jingzhuan.tableview.demo.lesson9 + +import android.content.Context +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import cn.jingzhuan.tableview.demo.elements.* +import cn.jingzhuan.tableview.element.Column +import io.reactivex.Flowable +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers + +class Lesson9ViewModel : ViewModel() { + + val liveData = MutableLiveData() + private var disposable: Disposable? = null + + fun fetch(context: Context, rowsCount: Int, columnsCount: Int) { + disposable = Flowable.fromCallable { columnsCount } + .map { + + val titleColumns = mutableListOf() + titleColumns.add(TitleHeaderColumn()) + for (i in 0 until columnsCount) { + val titleColumn = TitleColumn(i) + when (i) { + 0 -> titleColumn.weight = 1 + 1 -> titleColumn.weight = 1 + 2 -> titleColumn.weight = 0 + } + titleColumn.rightMargin = 10 + titleColumns.add(titleColumn) + } + val titleRow = TitleRow(titleColumns) + + for (rowIndex in 0 until rowsCount) { + val rowColumns = mutableListOf() + rowColumns.add(SimpleHeaderColumn("Row${rowIndex + 1}")) + for (columnIndex in 0 until columnsCount) { + if(columnIndex == 1) { + val column = Lesson9ViewColumn() + rowColumns.add(column) + } else { + val column = SimpleColumn("${rowIndex + 1} - ${columnIndex + 1}") + column.leftMargin = 40 + column.rightMargin = 10 + rowColumns.add(column) + } + } + titleRow.rows.add(SimpleRow(rowColumns)) + } + +// titleRow.preMeasureAllRows(context) + titleRow + } + .subscribeOn(Schedulers.computation()) + .subscribe({ + liveData.postValue(it) + }, { + + }) + } + + override fun onCleared() { + super.onCleared() + disposable?.dispose() + } + +} \ No newline at end of file diff --git a/app/src/main/java/cn/jingzhuan/tableview/demo/main/MainActivity.kt b/app/src/main/java/cn/jingzhuan/tableview/demo/main/MainActivity.kt index 4f3c605..d9ac09f 100644 --- a/app/src/main/java/cn/jingzhuan/tableview/demo/main/MainActivity.kt +++ b/app/src/main/java/cn/jingzhuan/tableview/demo/main/MainActivity.kt @@ -14,6 +14,8 @@ import cn.jingzhuan.tableview.demo.lesson5.Lesson5Activity import cn.jingzhuan.tableview.demo.lesson6.Lesson6Activity import cn.jingzhuan.tableview.demo.lesson7.Lesson7Activity import cn.jingzhuan.tableview.demo.lesson8.Lesson8Activity +import cn.jingzhuan.tableview.demo.lesson9.Lesson9Activity +import cn.jingzhuan.tableview.demo.lesson9.Lesson9ViewModel class MainActivity : AppCompatActivity() { @@ -32,6 +34,8 @@ class MainActivity : AppCompatActivity() { adapter.data.add("Lesson 6 - sticky rows") adapter.data.add("Lesson 7 - direction lock") adapter.data.add("Lesson 8 - dynamic value") + adapter.data.add("Lesson 9 - snap columns") + adapter.onItemClick = { when (it) { 0 -> startActivity(Intent(this, Lesson1Activity::class.java)) @@ -42,6 +46,7 @@ class MainActivity : AppCompatActivity() { 5 -> startActivity(Intent(this, Lesson6Activity::class.java)) 6 -> startActivity(Intent(this, Lesson7Activity::class.java)) 7 -> startActivity(Intent(this, Lesson8Activity::class.java)) + 8 -> startActivity(Intent(this, Lesson9Activity::class.java)) } } adapter.notifyDataSetChanged() diff --git a/app/src/main/res/layout/activity_lesson_9.xml b/app/src/main/res/layout/activity_lesson_9.xml new file mode 100644 index 0000000..3834dca --- /dev/null +++ b/app/src/main/res/layout/activity_lesson_9.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 0f123ea..ee15eb5 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -2,10 +2,16 @@ - + android:layout_height="match_parent"> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_lesson_9_view_column.xml b/app/src/main/res/layout/layout_lesson_9_view_column.xml new file mode 100644 index 0000000..b6dfbb0 --- /dev/null +++ b/app/src/main/res/layout/layout_lesson_9_view_column.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7fc1566..d64ab0a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip diff --git a/tableview/src/main/java/cn/jingzhuan/tableview/TableView.kt b/tableview/src/main/java/cn/jingzhuan/tableview/TableView.kt index 11b63f1..76caadf 100644 --- a/tableview/src/main/java/cn/jingzhuan/tableview/TableView.kt +++ b/tableview/src/main/java/cn/jingzhuan/tableview/TableView.kt @@ -7,6 +7,7 @@ import android.support.annotation.ColorInt import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView import android.util.AttributeSet +import android.util.Log import android.view.MotionEvent import android.view.View import android.view.ViewGroup.LayoutParams.MATCH_PARENT @@ -85,12 +86,24 @@ open class TableView @JvmOverloads constructor( setAdapter(adapter) setStretchMode(false) - header.layoutManager = RowListLayoutManager(context) { dx, _ -> - headerRow?.layoutManager?.scrollHorizontallyBy(dx) ?: 0 - } - main.layoutManager = RowListLayoutManager(context) { dx, _ -> - headerRow?.layoutManager?.scrollHorizontallyBy(dx) ?: 0 - } + header.layoutManager = RowListLayoutManager( + context, + onScrollHorizontallyBy = { dx, _ -> + headerRow?.layoutManager?.scrollHorizontallyBy(dx) ?: 0 + }, + onHorizontalScrollStateChanged = { state, dx -> + headerRow?.layoutManager?.onHorizontalScrollStateChanged(state, dx) ?: false + }, + ) + main.layoutManager = RowListLayoutManager( + context, + onScrollHorizontallyBy = { dx, _ -> + headerRow?.layoutManager?.scrollHorizontallyBy(dx) ?: 0 + }, + onHorizontalScrollStateChanged = { state, dx -> + headerRow?.layoutManager?.onHorizontalScrollStateChanged(state, dx) ?: false + }, + ) header.addOnScrollListener(scrollListener) main.addOnScrollListener(scrollListener) (header as DirectionLockRecyclerView).directionLockEnabled = true @@ -132,7 +145,11 @@ open class TableView @JvmOverloads constructor( } fun updateTableSize(columns: Int, stickyColumnsCount: Int) { - columnsLayoutManager.updateTableSize(columns, stickyColumnsCount) + updateTableSize(columns, stickyColumnsCount, 0) + } + + fun updateTableSize(columns: Int, stickyColumnsCount: Int, snapColumnsCount: Int) { + columnsLayoutManager.updateTableSize(columns, stickyColumnsCount, snapColumnsCount) } fun setRowsDividerEnabled( diff --git a/tableview/src/main/java/cn/jingzhuan/tableview/element/HeaderRow.kt b/tableview/src/main/java/cn/jingzhuan/tableview/element/HeaderRow.kt index 923e7aa..0cf2648 100644 --- a/tableview/src/main/java/cn/jingzhuan/tableview/element/HeaderRow.kt +++ b/tableview/src/main/java/cn/jingzhuan/tableview/element/HeaderRow.kt @@ -46,14 +46,19 @@ open class HeaderRow(columns: List) : Row(colum fun preMeasureAllRows(context: Context) { val layoutManager = layoutManager ?: return - measure(context, layoutManager.specs) - stickyRows.forEach { it.measure(context, layoutManager.specs) } - rows.forEach { it.measure(context, layoutManager.specs) } + var columnsWidthChanged = false + columnsWidthChanged = columnsWidthChanged or measure(context, layoutManager.specs) + stickyRows.forEach { columnsWidthChanged = columnsWidthChanged or it.measure(context, layoutManager.specs) } + rows.forEach { columnsWidthChanged = columnsWidthChanged or it.measure(context, layoutManager.specs) } + if(columnsWidthChanged) getTableSpecs()?.onColumnsWidthChanged() } fun preMeasureRow(context: Context, row: Row<*>) { val layoutManager = layoutManager ?: return - if (row.measure(context, layoutManager.specs)) row.forceLayout = true + if (row.measure(context, layoutManager.specs)) { + getTableSpecs()?.onColumnsWidthChanged() + row.forceLayout = true + } } fun preLayoutRowIfNecessary(context: Context, row: Row<*>) { diff --git a/tableview/src/main/java/cn/jingzhuan/tableview/element/Row.kt b/tableview/src/main/java/cn/jingzhuan/tableview/element/Row.kt index f02ff38..b5fb235 100644 --- a/tableview/src/main/java/cn/jingzhuan/tableview/element/Row.kt +++ b/tableview/src/main/java/cn/jingzhuan/tableview/element/Row.kt @@ -14,6 +14,7 @@ import cn.jingzhuan.tableview.layoutmanager.ColumnsLayoutManager import cn.jingzhuan.tableview.layoutmanager.TableSpecs import cn.jingzhuan.tableview.listeners.OnRowClickListener import cn.jingzhuan.tableview.listeners.OnRowLongClickListener +import timber.log.Timber import java.io.ObjectInputStream import kotlin.math.max import kotlin.math.min @@ -169,8 +170,7 @@ abstract class Row(var columns: List) : for (i in 0 until maxSize) { if (i == specs.stickyColumnsCount) x = 0 val column = columns[i] - layoutColumn(context, i, column, x, rowHeight, specs) - x = column.columnRight + x = layoutColumn(context, i, column, x, rowHeight, specs) } } @@ -192,10 +192,9 @@ abstract class Row(var columns: List) : for (i in 0 until specs.stickyColumnsCount) { if (!specs.isColumnVisible(i)) continue val column = columns[i] - layoutColumn(context, i, column, x, rowHeight, specs) + x = layoutColumn(context, i, column, x, rowHeight, specs) if (column is DrawableColumn) column.draw(context, canvas, rowShareElements) drawColumnsDivider(canvas, column, specs) - x = column.columnRight } } @@ -212,7 +211,7 @@ abstract class Row(var columns: List) : for (i in startIndex until specs.columnsCount) { if (!specs.isColumnVisible(i)) continue val column = columns[i] - layoutColumn(context, i, column, x, rowHeight, specs) + x = layoutColumn(context, i, column, x, rowHeight, specs) if (column is DrawableColumn) { if (column.columnLeft > container.scrollX + container.width) break if (!column.shouldIgnoreDraw(container)) { @@ -220,7 +219,6 @@ abstract class Row(var columns: List) : } } drawColumnsDivider(canvas, column, specs) - x = column.columnRight } } @@ -290,10 +288,12 @@ abstract class Row(var columns: List) : x: Int, rowHeight: Int, specs: TableSpecs - ) { - column.columnLeft = x + ): Int { + val snapWidth = if(specs.snapColumnsCount > 0 && index >= specs.stickyColumnsCount) specs.getSnapWidth() else 0 + val columnLeft = x - snapWidth + column.columnLeft = columnLeft column.columnTop = 0 - column.columnRight = x + specs.visibleColumnsWidth[index] + column.columnRight = columnLeft + specs.visibleColumnsWidth[index] column.columnBottom = rowHeight val top: Int @@ -338,6 +338,7 @@ abstract class Row(var columns: List) : if (column is DrawableColumn) { column.prepareToDraw(context, rowShareElements) } + return column.columnRight + snapWidth } private fun drawColumnsDivider(canvas: Canvas, column: Column, specs: TableSpecs) { diff --git a/tableview/src/main/java/cn/jingzhuan/tableview/layoutmanager/ColumnsLayoutManager.kt b/tableview/src/main/java/cn/jingzhuan/tableview/layoutmanager/ColumnsLayoutManager.kt index 40bfd5b..844537b 100644 --- a/tableview/src/main/java/cn/jingzhuan/tableview/layoutmanager/ColumnsLayoutManager.kt +++ b/tableview/src/main/java/cn/jingzhuan/tableview/layoutmanager/ColumnsLayoutManager.kt @@ -1,15 +1,19 @@ package cn.jingzhuan.tableview.layoutmanager +import android.animation.ValueAnimator import android.content.Context +import android.support.v7.widget.RecyclerView import android.view.View import android.view.View.MeasureSpec import android.view.ViewGroup +import android.view.animation.AccelerateDecelerateInterpolator import cn.jingzhuan.tableview.RowLayout import cn.jingzhuan.tableview.element.DrawableColumn import cn.jingzhuan.tableview.element.Row import cn.jingzhuan.tableview.element.ViewColumn import cn.jingzhuan.tableview.lazyNone import cn.jingzhuan.tableview.runOnMainThread +import timber.log.Timber import java.io.ObjectInputStream import java.io.Serializable import kotlin.math.max @@ -22,6 +26,9 @@ class ColumnsLayoutManager : Serializable { @Transient private var attachedRows = mutableSetOf() + @Transient + private var snapAnimator: ValueAnimator? = null + private val runnable = Runnable { attachedRows.forEach { it.layout() } } @@ -44,7 +51,15 @@ class ColumnsLayoutManager : Serializable { columnsSize: Int = this.specs.columnsCount, stickyColumns: Int = this.specs.stickyColumnsCount ) { - specs.updateTableSize(columnsSize, stickyColumns) + updateTableSize(columnsSize, stickyColumns, 0) + } + + fun updateTableSize( + columnsSize: Int = this.specs.columnsCount, + stickyColumns: Int = this.specs.stickyColumnsCount, + snapColumnsCount: Int = 0 + ) { + specs.updateTableSize(columnsSize, stickyColumns, snapColumnsCount) attachedRows.forEach { it.row?.forceLayout = true } } @@ -76,24 +91,83 @@ class ColumnsLayoutManager : Serializable { if (attachedRows.isEmpty()) return 0 val scrollRange = specs.computeScrollRange() val consumed = when { + specs.scrollX > 0 && dx < 0 && specs.scrollX < -dx -> { + -specs.scrollX + } + specs.scrollX < 0 && dx > 0 && -specs.scrollX < dx -> { + -specs.scrollX + } dx > 0 -> { val maxDx = scrollRange - specs.scrollX min(dx, maxDx) } dx < 0 -> { - val minDx = -specs.scrollX + val minDx = -specs.scrollX - specs.getSnapWidth() max(dx, minDx) } else -> 0 } if (consumed == 0 && specs.scrollX <= scrollRange) return 0 - specs.updateScrollX(specs.scrollX + consumed) - if (specs.scrollX > scrollRange) specs.updateScrollX(scrollRange) + val expectScrollX = specs.scrollX + consumed + if (expectScrollX > scrollRange) { + specs.updateScrollX(scrollRange) + } else { + specs.updateScrollX(expectScrollX) + } // 调整当前持有的所有RowLayout attachedRows.forEach { it.scrollTo(specs.scrollX, 0) } return consumed } + /** + * @return 返回 true 会停止 RecyclerView 的 ViewFlinger,然后可以开始执行 TableView 的 SnapScroll + */ + internal fun onHorizontalScrollStateChanged(state: Int, dx: Int): Boolean { + if (specs.snapColumnsCount <= 0) return false + if (state == RecyclerView.SCROLL_STATE_SETTLING && specs.scrollX < 0) { + val snapWidth = specs.getSnapWidth() + if (snapWidth <= 0) return false + snapAnimator?.cancel() + val endX = if (dx > 0) 0 else -snapWidth + val animator = ValueAnimator.ofInt(specs.scrollX, endX) + animator.interpolator = AccelerateDecelerateInterpolator() + animator.addUpdateListener { + val x = it.animatedValue as? Int ?: return@addUpdateListener + val animateDx = x - specs.scrollX + scrollHorizontallyBy(animateDx) + } + snapAnimator = animator + snapAnimator?.start() + return true + } else if (state == RecyclerView.SCROLL_STATE_IDLE && specs.scrollX < 0) { + if (snapAnimator?.isRunning == true) return true + val snapWidth = specs.getSnapWidth() + if (snapWidth <= 0) return false + snapAnimator?.cancel() + val endX = if (snapWidth + specs.scrollX > -specs.scrollX) 0 else -snapWidth + val animator = ValueAnimator.ofInt(specs.scrollX, endX) + animator.interpolator = AccelerateDecelerateInterpolator() + animator.addUpdateListener { + val x = it.animatedValue as? Int ?: return@addUpdateListener + val animateDx = x - specs.scrollX + scrollHorizontallyBy(animateDx) + } + snapAnimator = animator + snapAnimator?.start() + } + return false + } + + internal fun adjustSnapScrollXAfterColumnsWidthChanged() { + if(specs.scrollX >= 0) return + val snapWidth = specs.getSnapWidth() + if(snapWidth <= 0) return + val endX = if(snapWidth + specs.scrollX > -specs.scrollX) 0 else -snapWidth + if(specs.scrollX == endX) return + val dx = endX - specs.scrollX + scrollHorizontallyBy(dx) + } + internal fun measureAndLayout( context: Context, row: Row<*>, @@ -123,6 +197,7 @@ class ColumnsLayoutManager : Serializable { val column = row.columns[index] val sticky = index < specs.stickyColumnsCount + val snap = (index - specs.stickyColumnsCount) < specs.snapColumnsCount val visible = specs.isColumnVisible(index) if (column is DrawableColumn) { @@ -251,6 +326,7 @@ class ColumnsLayoutManager : Serializable { // 列宽发生变化或者第一次初始化,都需要Layout if (layoutOnly || pendingLayout || !initialized || row.forceLayout) { if (specs.stretchMode) specs.compareAndSetStretchColumnsWidth() + specs.compareAndSetSnapColumnsWidth() row.layout(context, specs) var viewIndex = 0 @@ -285,6 +361,8 @@ class ColumnsLayoutManager : Serializable { } else { scrollableContainer.postInvalidate() } + + if(pendingLayout) adjustSnapScrollXAfterColumnsWidthChanged() } /** diff --git a/tableview/src/main/java/cn/jingzhuan/tableview/layoutmanager/RowListLayoutManager.kt b/tableview/src/main/java/cn/jingzhuan/tableview/layoutmanager/RowListLayoutManager.kt index f0eb1eb..f9626b7 100644 --- a/tableview/src/main/java/cn/jingzhuan/tableview/layoutmanager/RowListLayoutManager.kt +++ b/tableview/src/main/java/cn/jingzhuan/tableview/layoutmanager/RowListLayoutManager.kt @@ -3,6 +3,7 @@ package cn.jingzhuan.tableview.layoutmanager import android.content.Context import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView +import android.util.Log /** * Chenyikang @@ -10,9 +11,15 @@ import android.support.v7.widget.RecyclerView */ internal class RowListLayoutManager( context: Context, - private val scrollHorizontallyBy: (dx: Int, remainingScrollHorizontal: Int) -> Int + // @return consumed dx + private val onScrollHorizontallyBy: (dx: Int, remainingScrollHorizontal: Int) -> Int, + // @return whether to stop scroller + private val onHorizontalScrollStateChanged: (state: Int, dx: Int) -> Boolean ) : LinearLayoutManager(context) { + private var lastScrollState = RecyclerView.SCROLL_STATE_IDLE + private var lastHorizontalScrollState = RecyclerView.SCROLL_STATE_IDLE + override fun canScrollVertically() = true override fun canScrollHorizontally() = true @@ -22,6 +29,19 @@ internal class RowListLayoutManager( recycler: RecyclerView.Recycler, state: RecyclerView.State ): Int { - return scrollHorizontallyBy.invoke(dx, state.remainingScrollHorizontal) + if (lastHorizontalScrollState != lastScrollState) { + lastHorizontalScrollState = lastScrollState + if(onHorizontalScrollStateChanged(lastHorizontalScrollState, dx)) return 0 + } + return onScrollHorizontallyBy.invoke(dx, state.remainingScrollHorizontal) + } + + override fun onScrollStateChanged(state: Int) { + super.onScrollStateChanged(state) + lastScrollState = state + if (state == RecyclerView.SCROLL_STATE_IDLE && lastHorizontalScrollState != RecyclerView.SCROLL_STATE_IDLE) { + lastHorizontalScrollState = state + onHorizontalScrollStateChanged(lastHorizontalScrollState, 0) + } } } \ No newline at end of file diff --git a/tableview/src/main/java/cn/jingzhuan/tableview/layoutmanager/TableSpecs.kt b/tableview/src/main/java/cn/jingzhuan/tableview/layoutmanager/TableSpecs.kt index 0976d2a..b388d65 100644 --- a/tableview/src/main/java/cn/jingzhuan/tableview/layoutmanager/TableSpecs.kt +++ b/tableview/src/main/java/cn/jingzhuan/tableview/layoutmanager/TableSpecs.kt @@ -1,12 +1,14 @@ package cn.jingzhuan.tableview.layoutmanager import android.graphics.Paint +import android.os.Handler import android.support.annotation.ColorInt import android.support.v7.widget.RecyclerView import android.util.Log import android.util.SparseIntArray import cn.jingzhuan.tableview.element.Column import cn.jingzhuan.tableview.element.HeaderRow +import timber.log.Timber import kotlin.math.max import kotlin.math.min @@ -16,11 +18,18 @@ class TableSpecs(private val layoutManager: ColumnsLayoutManager) { var headerRow: HeaderRow<*>? = null + // 列显示宽度 val visibleColumnsWidth = SparseIntArray() + + // 列实际测量宽度 private val realColumnsWidth = SparseIntArray() var stickyColumnsCount = 0 private set + + var snapColumnsCount = 0 + private set + var columnsCount = 0 private set @@ -102,10 +111,15 @@ class TableSpecs(private val layoutManager: ColumnsLayoutManager) { resetScrollableFirstVisibleColumn() } - internal fun updateTableSize(columnsCount: Int, stickyColumnsCount: Int) { + internal fun updateTableSize( + columnsCount: Int, + stickyColumnsCount: Int, + snapColumnsCount: Int = 0 + ) { if (stickyColumnsCount > columnsCount) throw IllegalArgumentException("stickyColumnsCount must not be greater than columnsCount") this.columnsCount = columnsCount this.stickyColumnsCount = stickyColumnsCount + this.snapColumnsCount = snapColumnsCount // 列数变化,重置 stretchMode 列宽 this.averageStretchColumnWidth = 0 visibleColumnsWidth.clear() @@ -116,12 +130,38 @@ class TableSpecs(private val layoutManager: ColumnsLayoutManager) { fun compareAndSetStretchColumnsWidth() { val stretchWidth = tableWidth - stickyWidth - for (i in stickyColumnsCount until columnsCount) { + for (i in stickyColumnsCount + snapColumnsCount until columnsCount) { val weight = realColumnsWidth[i] / realScrollableVirtualWidth.toFloat() visibleColumnsWidth.put(i, (weight * stretchWidth).toInt()) } } + fun compareAndSetSnapColumnsWidth() { + if (snapColumnsCount <= 0) return + val snapWidth = getSnapWidth() + var flexibleWidth = snapWidth + val flexibleWeights = mutableMapOf() + var totalWeight = 0F + for (i in stickyColumnsCount until stickyColumnsCount + snapColumnsCount) { + val weight = headerRow?.columns?.getOrNull(i)?.weight ?: 0 + flexibleWeights[i] = weight + totalWeight += weight + if (weight == 0 && isColumnVisible(i)) { + flexibleWidth -= visibleColumnsWidth[i] + } + } + var snapTotalWidth = 0 + for (i in stickyColumnsCount until stickyColumnsCount + snapColumnsCount) { + val weight = flexibleWeights[i] ?: 0 + if (weight <= 0) { + snapTotalWidth += visibleColumnsWidth[i] + continue + } + visibleColumnsWidth.put(i, (flexibleWidth * (weight / totalWeight)).toInt()) + snapTotalWidth += visibleColumnsWidth[i] + } + } + /** * @return whether [visibleColumnsWidth] have been changed */ @@ -198,7 +238,8 @@ class TableSpecs(private val layoutManager: ColumnsLayoutManager) { fun computeScrollRange(): Int { if (stretchMode) return 0 - return max(0, visibleScrollableVirtualWidth - (tableWidth - stickyWidth)) + val times = if (snapColumnsCount > 0) 2 else 1 + return max(0, visibleScrollableVirtualWidth - (tableWidth - stickyWidth) * times) } fun onColumnsWidthChanged() { @@ -228,4 +269,8 @@ class TableSpecs(private val layoutManager: ColumnsLayoutManager) { } } + internal fun getSnapWidth(): Int { + return if (snapColumnsCount <= 0) 0 else max(0, tableWidth - stickyWidth) + } + } \ No newline at end of file diff --git a/updateLibsAndRun b/updateLibsAndRun index 2ad69c1..26ac947 100644 --- a/updateLibsAndRun +++ b/updateLibsAndRun @@ -3,6 +3,7 @@ ./gradlew clean ./gradlew :tableview:assembleRelease ./jetifier-standalone/bin/jetifier-standalone -i "tableview/build/outputs/aar/tableview-release.aar" -o "app/libs/jz-tableview-release-jetified.aar" -./gradlew :app:assembleDebug -adb install -r -t app/build/outputs/apk/debug/app-debug.apk +#./gradlew :app:assembleDebug +#adb install -r -t app/build/outputs/apk/debug/app-debug.apk +./gradlew :app:installDebug adb shell am start -n cn.jingzhuan.tableview.demo/.main.MainActivity \ No newline at end of file