Skip to content

Commit 358ea55

Browse files
committed
perf: optimize horizontal scrolling performance and accuracy
- Remove redundant width calculations and tag usage - Implement efficient max width tracking and layout updates - Add scroll listener to dynamically adjust max width- Improve item measurement and layout during horizontal scrolling
1 parent bf4ebea commit 358ea55

File tree

1 file changed

+62
-22
lines changed
  • treeview/src/main/kotlin/io/github/dingyi222666/view/treeview

1 file changed

+62
-22
lines changed

treeview/src/main/kotlin/io/github/dingyi222666/view/treeview/TreeView.kt

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ class TreeView<T : Any>(context: Context, attrs: AttributeSet?, defStyleAttr: In
4848
)
4949

5050
private var horizontalOffset = 0f
51-
private var maxChildWidth = 0f
51+
private var maxChildWidth = 0
5252
private var pointerId = 0
5353
private var pointerLastX = 0f
5454
private var slopExceeded = false
55-
private val maxHorizontalOffset
55+
private var needsWidthRefresh = true
56+
57+
private val maxHorizontalOffset: Float
5658
get() = (maxChildWidth - width * 0.75f).coerceAtLeast(0f)
5759

5860
/**
@@ -140,11 +142,21 @@ class TreeView<T : Any>(context: Context, attrs: AttributeSet?, defStyleAttr: In
140142
private var initialTouchY = 0f
141143
private val touchSlop = ViewConfiguration.get(context).scaledTouchSlop
142144

145+
private val scrollListener = object : OnScrollListener() {
146+
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
147+
if (supportHorizontalScroll) {
148+
recalculateMaxWidth()
149+
}
150+
}
151+
}
152+
143153
init {
144154
this._itemTouchHelperCallback = ItemTouchHelperCallback()
145155

146156
val itemTouchHelper = ItemTouchHelper(_itemTouchHelperCallback)
147157
itemTouchHelper.attachToRecyclerView(this)
158+
159+
addOnScrollListener(scrollListener)
148160
}
149161

150162
/**
@@ -365,17 +377,9 @@ class TreeView<T : Any>(context: Context, attrs: AttributeSet?, defStyleAttr: In
365377

366378
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
367379
super.onLayout(changed, l, t, r, b)
368-
if (supportHorizontalScroll) {
369-
// Fetch children sizes and update max size of children
370-
var maxWidth = 0
371-
for (i in 0 until childCount) {
372-
maxWidth = maxWidth.coerceAtLeast(
373-
getChildAt(i).getTag(R.id.tag_measured_width) as Int? ?: 0
374-
)
375-
}
376-
maxChildWidth = maxWidth.toFloat()
377-
} else {
378-
maxChildWidth = 0f
380+
if (supportHorizontalScroll && (changed || needsWidthRefresh)) {
381+
recalculateMaxWidth()
382+
needsWidthRefresh = false
379383
}
380384
}
381385

@@ -814,26 +818,31 @@ class TreeView<T : Any>(context: Context, attrs: AttributeSet?, defStyleAttr: In
814818

815819
if (supportHorizontalScroll) {
816820
holder.itemView.apply {
817-
// Get child's preferred size
821+
// First measure with wrap content to get actual content width
818822
updateLayoutParams<ViewGroup.LayoutParams> {
819823
width = LayoutParams.WRAP_CONTENT
820824
height = LayoutParams.WRAP_CONTENT
821825
}
826+
822827
measure(
823828
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
824829
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
825830
)
826-
// Apply a large width and measured height
831+
832+
val measuredWidth = measuredWidth
833+
834+
// Set width to a large value to ensure item fills available space
827835
updateLayoutParams<ViewGroup.LayoutParams> {
828-
width = 1000000
829-
height = holder.itemView.measuredHeight
836+
width = 1000000 // Use large fixed width
837+
height = measuredHeight
838+
}
830839

840+
// Update max width if needed
841+
if (measuredWidth > maxChildWidth) {
842+
maxChildWidth = measuredWidth
843+
needsWidthRefresh = true
844+
post { requestLayout() }
831845
}
832-
// Save current measured width for later usage
833-
setTag(
834-
R.id.tag_measured_width,
835-
holder.itemView.measuredWidth
836-
)
837846
}
838847
} else {
839848
holder.itemView.updateLayoutParams<ViewGroup.LayoutParams> {
@@ -843,6 +852,14 @@ class TreeView<T : Any>(context: Context, attrs: AttributeSet?, defStyleAttr: In
843852
}
844853
}
845854

855+
override fun onViewAttachedToWindow(holder: ViewHolder) {
856+
super.onViewAttachedToWindow(holder)
857+
if (supportHorizontalScroll) {
858+
needsWidthRefresh = true
859+
holder.itemView.post { requestLayout() }
860+
}
861+
}
862+
846863
override fun getItemId(position: Int): Long {
847864
return getItem(position).id.toLong()
848865
}
@@ -932,6 +949,29 @@ class TreeView<T : Any>(context: Context, attrs: AttributeSet?, defStyleAttr: In
932949
*/
933950
MULTIPLE_WITH_CHILDREN,
934951
}
952+
953+
private fun recalculateMaxWidth() {
954+
if (!supportHorizontalScroll) {
955+
maxChildWidth = 0
956+
return
957+
}
958+
959+
var maxWidth = 0
960+
for (i in 0 until childCount) {
961+
val child = getChildAt(i)
962+
val holder = getChildViewHolder(child) as? ViewHolder ?: continue
963+
val position = holder.adapterPosition
964+
if (position == NO_POSITION) continue
965+
966+
// Get the measured width including padding and margins
967+
val itemWidth = child.measuredWidth + child.paddingLeft + child.paddingRight
968+
maxWidth = maxWidth.coerceAtLeast(itemWidth)
969+
}
970+
971+
if (maxWidth > 0) {
972+
maxChildWidth = maxWidth
973+
}
974+
}
935975
}
936976

937977
/**

0 commit comments

Comments
 (0)