diff --git a/treeview/src/main/kotlin/io/github/dingyi222666/view/treeview/TreeView.kt b/treeview/src/main/kotlin/io/github/dingyi222666/view/treeview/TreeView.kt index 357f6dd..474a559 100644 --- a/treeview/src/main/kotlin/io/github/dingyi222666/view/treeview/TreeView.kt +++ b/treeview/src/main/kotlin/io/github/dingyi222666/view/treeview/TreeView.kt @@ -48,11 +48,13 @@ class TreeView(context: Context, attrs: AttributeSet?, defStyleAttr: In ) private var horizontalOffset = 0f - private var maxChildWidth = 0f + private var maxChildWidth = 0 private var pointerId = 0 private var pointerLastX = 0f private var slopExceeded = false - private val maxHorizontalOffset + private var needsWidthRefresh = true + + private val maxHorizontalOffset: Float get() = (maxChildWidth - width * 0.75f).coerceAtLeast(0f) /** @@ -140,11 +142,21 @@ class TreeView(context: Context, attrs: AttributeSet?, defStyleAttr: In private var initialTouchY = 0f private val touchSlop = ViewConfiguration.get(context).scaledTouchSlop + private val scrollListener = object : OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + if (supportHorizontalScroll) { + recalculateMaxWidth() + } + } + } + init { this._itemTouchHelperCallback = ItemTouchHelperCallback() val itemTouchHelper = ItemTouchHelper(_itemTouchHelperCallback) itemTouchHelper.attachToRecyclerView(this) + + addOnScrollListener(scrollListener) } /** @@ -365,17 +377,9 @@ class TreeView(context: Context, attrs: AttributeSet?, defStyleAttr: In override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { super.onLayout(changed, l, t, r, b) - if (supportHorizontalScroll) { - // Fetch children sizes and update max size of children - var maxWidth = 0 - for (i in 0 until childCount) { - maxWidth = maxWidth.coerceAtLeast( - getChildAt(i).getTag(R.id.tag_measured_width) as Int? ?: 0 - ) - } - maxChildWidth = maxWidth.toFloat() - } else { - maxChildWidth = 0f + if (supportHorizontalScroll && (changed || needsWidthRefresh)) { + recalculateMaxWidth() + needsWidthRefresh = false } } @@ -814,26 +818,31 @@ class TreeView(context: Context, attrs: AttributeSet?, defStyleAttr: In if (supportHorizontalScroll) { holder.itemView.apply { - // Get child's preferred size + // First measure with wrap content to get actual content width updateLayoutParams { width = LayoutParams.WRAP_CONTENT height = LayoutParams.WRAP_CONTENT } + measure( MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) ) - // Apply a large width and measured height + + val measuredWidth = measuredWidth + + // Set width to a large value to ensure item fills available space updateLayoutParams { - width = 1000000 - height = holder.itemView.measuredHeight + width = 1000000 // Use large fixed width + height = measuredHeight + } + // Update max width if needed + if (measuredWidth > maxChildWidth) { + maxChildWidth = measuredWidth + needsWidthRefresh = true + post { requestLayout() } } - // Save current measured width for later usage - setTag( - R.id.tag_measured_width, - holder.itemView.measuredWidth - ) } } else { holder.itemView.updateLayoutParams { @@ -843,6 +852,14 @@ class TreeView(context: Context, attrs: AttributeSet?, defStyleAttr: In } } + override fun onViewAttachedToWindow(holder: ViewHolder) { + super.onViewAttachedToWindow(holder) + if (supportHorizontalScroll) { + needsWidthRefresh = true + holder.itemView.post { requestLayout() } + } + } + override fun getItemId(position: Int): Long { return getItem(position).id.toLong() } @@ -932,6 +949,29 @@ class TreeView(context: Context, attrs: AttributeSet?, defStyleAttr: In */ MULTIPLE_WITH_CHILDREN, } + + private fun recalculateMaxWidth() { + if (!supportHorizontalScroll) { + maxChildWidth = 0 + return + } + + var maxWidth = 0 + for (i in 0 until childCount) { + val child = getChildAt(i) + val holder = getChildViewHolder(child) as? ViewHolder ?: continue + val position = holder.adapterPosition + if (position == NO_POSITION) continue + + // Get the measured width including padding and margins + val itemWidth = child.measuredWidth + child.paddingLeft + child.paddingRight + maxWidth = maxWidth.coerceAtLeast(itemWidth) + } + + if (maxWidth > 0) { + maxChildWidth = maxWidth + } + } } /**