From ce45b7144849847efa900b3d121eb88c973f8cc2 Mon Sep 17 00:00:00 2001 From: renhaoting <370797079@qq.com> Date: Fri, 31 Oct 2025 15:45:40 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AD=97=E4=BD=93=E9=80=89=E6=8B=A9=E5=99=A8?= =?UTF-8?q?=20=E5=9B=9E=E8=B0=83=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../visualnovel/ui/chat/ui/FontSetView.kt | 54 +++---- .../visualnovel/ui/chat/ui/LevelSeekbar.kt | 145 ++++++------------ .../visualnovel/ui/chat/ui/MaxNumView.kt | 4 +- .../main/res/layout/layout_font_set_view.xml | 4 +- 4 files changed, 72 insertions(+), 135 deletions(-) diff --git a/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/FontSetView.kt b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/FontSetView.kt index a2c1d25..9e98540 100644 --- a/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/FontSetView.kt +++ b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/FontSetView.kt @@ -14,17 +14,18 @@ class FontSetView @JvmOverloads constructor( ) : LinearLayout(context, attrs, defStyleAttr) { companion object { - private var GAP = 2 + private const val GAP = 2 + private const val MIN_VALUE = 12 + private const val MAX_VALUE = 20 } - private var mBinding: LayoutFontSetViewBinding + private var mBinding: LayoutFontSetViewBinding = + LayoutFontSetViewBinding.inflate(LayoutInflater.from(context), this, true) - private var mFontValue = 16 // 12, 14, 16, 18, 20 - private val mFontMinValue = 16 - private val mFontMaxValue = 20 + + private var mFontValue = MIN_VALUE + GAP * 2 init { - mBinding = LayoutFontSetViewBinding.inflate(LayoutInflater.from(context), this, true) setupClickListeners() } @@ -33,47 +34,32 @@ class FontSetView @JvmOverloads constructor( private fun setupClickListeners() { with (mBinding) { - ivFontPlus.setOnClickListener { - if (mFontValue > mFontMinValue) { + ivFontMinus.setOnClickListener { + if (mFontValue > MIN_VALUE) { mFontValue -= GAP } tvFontValue.text = mFontValue.toString() - levelSeekbar.setLevel((mFontValue - 16)/GAP) + levelSeekbar.setLevel((mFontValue - MIN_VALUE)/GAP) } ivFontAdd.setOnClickListener { - if (mFontValue < mFontMinValue) { + if (mFontValue < MAX_VALUE) { mFontValue += GAP } tvFontValue.text = mFontValue.toString() - levelSeekbar.setLevel((mFontValue - 16)/GAP) + levelSeekbar.setLevel((mFontValue - MIN_VALUE)/GAP) } - levelSeekbar.setOnLevelChangeListener(object : LevelSeekBar.OnLevelChangeListener { - override fun onLevelChanged( - seekBar: LevelSeekBar, - level: Int, - fromUser: Boolean - ) { - mFontValue = 16 + level * GAP - if (mFontValue > mFontMaxValue) { - mFontValue = mFontMaxValue - } - if (mFontValue < mFontMinValue) { - mFontValue = mFontMinValue - } - tvFontValue.text = mFontValue.toString() + levelSeekbar.setOnLevelChangeListener { level-> + mFontValue = 16 + level * GAP + if (mFontValue > MAX_VALUE) { + mFontValue = MAX_VALUE } - - override fun onStartTrackingTouch(seekBar: LevelSeekBar) { - + if (mFontValue < MIN_VALUE) { + mFontValue = MIN_VALUE } - - override fun onStopTrackingTouch(seekBar: LevelSeekBar) { - - } - - }) + tvFontValue.text = mFontValue.toString() + } } } diff --git a/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/LevelSeekbar.kt b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/LevelSeekbar.kt index dbb0002..459b592 100644 --- a/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/LevelSeekbar.kt +++ b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/LevelSeekbar.kt @@ -12,14 +12,15 @@ import com.remax.visualnovel.utils.spannablex.utils.dp import androidx.core.content.withStyledAttributes + class LevelSeekBar @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { - private var totalLevels = 5 - private var currentLevel = 2 + private var mTotalLevel = 5 + private var mCurLevel = 2 // 尺寸 private var trackHeight = ResUtil.getPixelSize(R.dimen.dp_5).toFloat() @@ -46,32 +47,25 @@ class LevelSeekBar @JvmOverloads constructor( // 监听器 private var onLevelChangeListener: OnLevelChangeListener? = null - private var isDragging = false - - - // 触摸相关 private var lastTouchX = 0f interface OnLevelChangeListener { - fun onLevelChanged(seekBar: LevelSeekBar, level: Int, fromUser: Boolean) - fun onStartTrackingTouch(seekBar: LevelSeekBar) - fun onStopTrackingTouch(seekBar: LevelSeekBar) + fun onLevelChanged(level: Int) } init { setupAttributes(attrs) setupPaints() - setBackgroundResource(R.color.red_ff3b30) } private fun setupAttributes(attrs: AttributeSet?) { attrs?.let { context.withStyledAttributes(it, R.styleable.CustomLevelSeekBar) { - totalLevels = getInt(R.styleable.CustomLevelSeekBar_totalLevels, totalLevels) - currentLevel = getInt(R.styleable.CustomLevelSeekBar_currentLevel, currentLevel) - .coerceIn(0, totalLevels - 1) + mTotalLevel = getInt(R.styleable.CustomLevelSeekBar_totalLevels, mTotalLevel) + mCurLevel = getInt(R.styleable.CustomLevelSeekBar_currentLevel, mCurLevel) + .coerceIn(0, mTotalLevel - 1) trackColor = getColor(R.styleable.CustomLevelSeekBar_trackColor, trackColor) activeTrackColor = @@ -118,124 +112,94 @@ class LevelSeekBar @JvmOverloads constructor( } private fun drawNodes(canvas: Canvas) { - if (totalLevels <= 1) return + if (mTotalLevel <= 1) return val centerY = height / 2f - for (i in 0 until totalLevels) { + for (i in 0 until mTotalLevel) { val x = calculatePositionForLevel(i) - nodePaint.color = if (i <= currentLevel) activeNodeColor else nodeColor - //canvas.drawCircle(x, centerY, nodeRadius, nodePaint) - val trackRect = RectF(x - nodeWidth/2, centerY - nodeHeight/2 + 6, x + nodeWidth/2, centerY + nodeHeight/2) + nodePaint.color = if (i <= mCurLevel) activeNodeColor else nodeColor + val trackRect = RectF(x - nodeWidth/2, centerY - nodeHeight/2, x + nodeWidth/2, centerY + nodeHeight/2) canvas.drawRoundRect(trackRect, trackEndRadius, trackEndRadius, nodePaint) } } private fun drawThumb(canvas: Canvas) { - if (totalLevels <= 1) return + if (mTotalLevel <= 1) return val centerY = height / 2f - val thumbX = calculatePositionForLevel(currentLevel) + val thumbX = calculatePositionForLevel(mCurLevel) canvas.drawCircle(thumbX, centerY, thumbRadius - 1F.dp.toFloat(), thumbPaint) } private fun calculatePositionForLevel(level: Int): Float { - if (totalLevels <= 1) return width / 2f + if (mTotalLevel <= 1) return width / 2f val availableWidth = width - 2 * thumbRadius - return thumbRadius + (availableWidth * level.toFloat() / (totalLevels - 1)) + return thumbRadius + (availableWidth * level.toFloat() / (mTotalLevel - 1)) } override fun onTouchEvent(event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> { - if (isPointInThumb(event.x, event.y) || isPointInTrack(event.x, event.y)) { - isDragging = true - lastTouchX = event.x - onLevelChangeListener?.onStartTrackingTouch(this) - handleTouch(event.x) - parent?.requestDisallowInterceptTouchEvent(true) - return true - } + lastTouchX = event.x + handleTouch(event.x) + parent?.requestDisallowInterceptTouchEvent(true) + return true } MotionEvent.ACTION_MOVE -> { - if (isDragging) { - lastTouchX = event.x - handleTouch(event.x) - return true - } + lastTouchX = event.x + handleTouch(event.x) + return true } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { - if (isDragging) { - isDragging = false - snapToNearestLevel(lastTouchX) - onLevelChangeListener?.onStopTrackingTouch(this) - parent?.requestDisallowInterceptTouchEvent(false) - return true - } + snapToNearestLevel(lastTouchX) + parent?.requestDisallowInterceptTouchEvent(false) + return true } } return super.onTouchEvent(event) } - private fun isPointInThumb(x: Float, y: Float): Boolean { - val thumbX = calculatePositionForLevel(currentLevel) - val centerY = height / 2f - val distance = Math.sqrt( - (x - thumbX) * (x - thumbX) + (y - centerY) * (y - centerY).toDouble() - ) - return distance <= thumbRadius - } - - private fun isPointInTrack(x: Float, y: Float): Boolean { - val centerY = height / 2f - val trackTop = centerY - trackHeight / 2 - thumbRadius // 扩大触摸区域 - val trackBottom = centerY + trackHeight / 2 + thumbRadius - return x in 0f..width.toFloat() && y in trackTop..trackBottom - } - private fun handleTouch(x: Float) { - if (totalLevels <= 1) return + if (mTotalLevel <= 1) return val newLevel = calculateLevelForPosition(x) - if (newLevel != currentLevel) { - currentLevel = newLevel + if (newLevel != mCurLevel) { + mCurLevel = newLevel invalidate() - onLevelChangeListener?.onLevelChanged(this, currentLevel, true) } } private fun snapToNearestLevel(x: Float) { - if (totalLevels <= 1) return + if (mTotalLevel <= 1) return val exactLevel = calculateExactLevelForPosition(x) - val newLevel = (exactLevel + 0.5f).toInt().coerceIn(0, totalLevels - 1) + val newLevel = (exactLevel + 0.5f).toInt().coerceIn(0, mTotalLevel - 1) - if (newLevel != currentLevel) { - currentLevel = newLevel - invalidate() - onLevelChangeListener?.onLevelChanged(this, currentLevel, true) - } + mCurLevel = newLevel + invalidate() + onLevelChangeListener?.onLevelChanged(mCurLevel) } private fun calculateLevelForPosition(x: Float): Int { - if (totalLevels <= 1) return 0 + if (mTotalLevel <= 1) return 0 val availableWidth = width - 2 * thumbRadius val progress = ((x - thumbRadius) / availableWidth).coerceIn(0f, 1f) - return (progress * (totalLevels - 1)).toInt().coerceIn(0, totalLevels - 1) + return (progress * (mTotalLevel - 1)).toInt().coerceIn(0, mTotalLevel - 1) } private fun calculateExactLevelForPosition(x: Float): Float { - if (totalLevels <= 1) return 0f + if (mTotalLevel <= 1) return 0f val availableWidth = width - 2 * thumbRadius val progress = ((x - thumbRadius) / availableWidth).coerceIn(0f, 1f) - return progress * (totalLevels - 1) + return progress * (mTotalLevel - 1) } @@ -243,45 +207,32 @@ class LevelSeekBar @JvmOverloads constructor( //---------------------------- public 设置方法 ---------------------------------// fun setLevel(level: Int, fromUser: Boolean = false) { - val newLevel = level.coerceIn(0, totalLevels - 1) - if (newLevel != currentLevel) { - currentLevel = newLevel + val newLevel = level.coerceIn(0, mTotalLevel - 1) + if (newLevel != mCurLevel) { + mCurLevel = newLevel invalidate() - onLevelChangeListener?.onLevelChanged(this, currentLevel, fromUser) } } - fun getLevel(): Int = currentLevel + fun getLevel(): Int = mCurLevel fun setTotalLevels(levels: Int) { - if (levels > 0 && levels != totalLevels) { - totalLevels = levels - currentLevel = currentLevel.coerceIn(0, totalLevels - 1) + if (levels > 0 && levels != mTotalLevel) { + mTotalLevel = levels + mCurLevel = mCurLevel.coerceIn(0, mTotalLevel - 1) invalidate() } } - fun getTotalLevels(): Int = totalLevels - - fun setOnLevelChangeListener(listener: OnLevelChangeListener) { - this.onLevelChangeListener = listener - } + fun getTotalLevels(): Int = mTotalLevel fun setOnLevelChangeListener( - onLevelChanged: (LevelSeekBar, Int, Boolean) -> Unit = { _, _, _ -> }, - onStartTrackingTouch: (LevelSeekBar) -> Unit = {}, - onStopTrackingTouch: (LevelSeekBar) -> Unit = {} + onLevelChanged: (Int) -> Unit ) { this.onLevelChangeListener = object : OnLevelChangeListener { - override fun onLevelChanged(seekBar: LevelSeekBar, level: Int, fromUser: Boolean) { - onLevelChanged(seekBar, level, fromUser) - } - override fun onStartTrackingTouch(seekBar: LevelSeekBar) { - onStartTrackingTouch(seekBar) - } - override fun onStopTrackingTouch(seekBar: LevelSeekBar) { - onStopTrackingTouch(seekBar) + override fun onLevelChanged(level: Int) { + onLevelChanged(level) } } } diff --git a/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/MaxNumView.kt b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/MaxNumView.kt index ccf75cf..d138a5c 100644 --- a/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/MaxNumView.kt +++ b/VisualNovel/app/src/main/java/com/remax/visualnovel/ui/chat/ui/MaxNumView.kt @@ -38,14 +38,14 @@ class MaxNumView @JvmOverloads constructor( private fun setupClickListeners() { with (mBinding) { ivLeftIcon.setOnClickListener { - mCurIndex = mCurIndex.takeUnless { it > 0 }?.minus(1) ?: mCurIndex + mCurIndex = mCurIndex.takeIf { it > 0 }?.minus(1) ?: mCurIndex mCurValue = mFixedValueList[mCurIndex] tvCenter.text = mCurValue.toString() mEventListener?.onValueChanged(mCurValue) } ivRightIcon.setOnClickListener { - mCurIndex = mCurIndex.takeUnless { it < mFixedValueList.size }?.plus(1) ?: mCurIndex + mCurIndex = mCurIndex.takeIf { it < mFixedValueList.size - 1 }?.plus(1) ?: mCurIndex mCurValue = mFixedValueList[mCurIndex] tvCenter.text = mCurValue.toString() mEventListener?.onValueChanged(mCurValue) diff --git a/VisualNovel/app/src/main/res/layout/layout_font_set_view.xml b/VisualNovel/app/src/main/res/layout/layout_font_set_view.xml index b5df59d..f7bac1f 100644 --- a/VisualNovel/app/src/main/res/layout/layout_font_set_view.xml +++ b/VisualNovel/app/src/main/res/layout/layout_font_set_view.xml @@ -65,7 +65,7 @@ android:layout_toEndOf="@+id/left_container" android:layout_marginTop="@dimen/dp_10">