更新界面
This commit is contained in:
1 parent
3516af6a9f
commit
3c494cfc9a
24 files changed
+666
-302
No files matched your search
@@ -2,24 +2,16 @@ package io.legato.kazusa.ui.widget
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.SeekBar
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.widget.TooltipCompat
|
||||
import com.google.android.material.slider.Slider
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.databinding.ViewDetailSeekBarBinding
|
||||
//import io.legado.app.lib.theme.bottomBackground
|
||||
//import io.legado.app.lib.theme.getPrimaryTextColor
|
||||
import io.legato.kazusa.ui.widget.seekbar.SeekBarChangeListener
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
class DetailSeekBar @JvmOverloads constructor(
|
||||
context: Context,
|
||||
@@ -31,6 +23,11 @@ class DetailSeekBar @JvmOverloads constructor(
|
||||
private val isBottomBackground: Boolean
|
||||
|
||||
var valueFormat: ((progress: Int) -> String)? = null
|
||||
set(value) {
|
||||
field = value
|
||||
upValue()
|
||||
}
|
||||
|
||||
var onStartTracking: (() -> Unit)? = null
|
||||
var onChanged: ((progress: Int) -> Unit)? = null
|
||||
var onStopTracking: (() -> Unit)? = null
|
||||
@@ -39,7 +36,6 @@ class DetailSeekBar @JvmOverloads constructor(
|
||||
get() = binding.slider.value.toInt()
|
||||
set(value) {
|
||||
binding.slider.value = value.toFloat()
|
||||
upValue()
|
||||
}
|
||||
|
||||
var max: Int
|
||||
@@ -54,7 +50,6 @@ class DetailSeekBar @JvmOverloads constructor(
|
||||
typedArray.getBoolean(R.styleable.DetailSeekBar_isBottomBackground, false)
|
||||
val title = typedArray.getText(R.styleable.DetailSeekBar_title)
|
||||
|
||||
|
||||
binding.tvSeekTitle.apply {
|
||||
text = title
|
||||
TooltipCompat.setTooltipText(this, title)
|
||||
@@ -93,23 +88,6 @@ class DetailSeekBar @JvmOverloads constructor(
|
||||
}
|
||||
})
|
||||
|
||||
binding.slider.setOnTouchListener { _, event ->
|
||||
if (event.action == MotionEvent.ACTION_DOWN) {
|
||||
val slider = binding.slider
|
||||
val sliderWidth = slider.width - slider.paddingStart - slider.paddingEnd
|
||||
val touchX = event.x - slider.paddingStart
|
||||
|
||||
val proportion = (slider.value - slider.valueFrom) / (slider.valueTo - slider.valueFrom)
|
||||
val thumbCenterX = proportion * sliderWidth
|
||||
|
||||
val thumbRadiusPx = slider.thumbRadius * 2f // 可适当扩大滑块判断区域
|
||||
|
||||
val isTouchNearThumb = kotlin.math.abs(touchX - thumbCenterX) <= thumbRadiusPx
|
||||
return@setOnTouchListener !isTouchNearThumb // 拦截不是点在滑块上的点击
|
||||
}
|
||||
return@setOnTouchListener false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun upValue(progress: Int = binding.slider.value.toInt()) {
|
||||
@@ -124,4 +102,8 @@ class DetailSeekBar @JvmOverloads constructor(
|
||||
upValue(progress)
|
||||
}
|
||||
|
||||
fun setTitle(title: CharSequence?) {
|
||||
binding.tvSeekTitle.text = title
|
||||
TooltipCompat.setTooltipText(binding.tvSeekTitle, title)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
package io.legato.kazusa.ui.widget
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.widget.FrameLayout
|
||||
import androidx.appcompat.widget.TooltipCompat
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.databinding.ViewSimpleCounterBinding
|
||||
import io.legato.kazusa.lib.dialogs.alert
|
||||
|
||||
@SuppressLint("ViewConstructor", "ClickableViewAccessibility")
|
||||
class SimpleCounterView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) : FrameLayout(context, attrs) {
|
||||
|
||||
private val binding = ViewSimpleCounterBinding.inflate(LayoutInflater.from(context), this)
|
||||
|
||||
private var _progress = 0
|
||||
private var _max = 100
|
||||
private val isBottomBackground: Boolean
|
||||
|
||||
var valueFormat: ((Int) -> String)? = null
|
||||
var onChanged: ((Int) -> Unit)? = null
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private var isIncrementing = false
|
||||
private var isDecrementing = false
|
||||
|
||||
private val longPressDelay = 400L
|
||||
private val repeatInterval = 320L
|
||||
|
||||
|
||||
var progress: Int
|
||||
get() = _progress
|
||||
set(value) {
|
||||
_progress = value.coerceIn(0, _max)
|
||||
updateValue()
|
||||
}
|
||||
|
||||
var max: Int
|
||||
get() = _max
|
||||
set(value) {
|
||||
_max = value
|
||||
_progress = _progress.coerceAtMost(_max)
|
||||
updateValue()
|
||||
}
|
||||
|
||||
init {
|
||||
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.DetailSeekBar)
|
||||
isBottomBackground = typedArray.getBoolean(R.styleable.DetailSeekBar_isBottomBackground, false)
|
||||
val title = typedArray.getText(R.styleable.DetailSeekBar_title)
|
||||
_max = typedArray.getInt(R.styleable.DetailSeekBar_max, 100)
|
||||
typedArray.recycle()
|
||||
|
||||
binding.tvSeekTitle.text = title
|
||||
TooltipCompat.setTooltipText(binding.tvSeekTitle, title)
|
||||
|
||||
binding.ivSeekPlus.setOnClickListener {
|
||||
if (_progress < _max) {
|
||||
_progress++
|
||||
updateValue()
|
||||
onChanged?.invoke(_progress)
|
||||
}
|
||||
}
|
||||
|
||||
binding.ivSeekReduce.setOnClickListener {
|
||||
if (_progress > 0) {
|
||||
_progress--
|
||||
updateValue()
|
||||
onChanged?.invoke(_progress)
|
||||
}
|
||||
}
|
||||
|
||||
binding.ivSeekPlus.setOnTouchListener { _, event ->
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
isIncrementing = true
|
||||
handler.postDelayed(startIncrementRunnable, longPressDelay)
|
||||
}
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
||||
isIncrementing = false
|
||||
handler.removeCallbacks(startIncrementRunnable)
|
||||
handler.removeCallbacks(incrementRunnable)
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
binding.ivSeekReduce.setOnTouchListener { _, event ->
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
isDecrementing = true
|
||||
handler.postDelayed(startDecrementRunnable, longPressDelay)
|
||||
}
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
||||
isDecrementing = false
|
||||
handler.removeCallbacks(startDecrementRunnable)
|
||||
handler.removeCallbacks(decrementRunnable)
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
binding.tvSeekValue.setOnClickListener {
|
||||
showSeekBarDialog()
|
||||
}
|
||||
|
||||
updateValue()
|
||||
}
|
||||
|
||||
private fun showSeekBarDialog() {
|
||||
context.alert(title = null, message = null) {
|
||||
customView {
|
||||
val detailSeekBar = DetailSeekBar(ctx).apply {
|
||||
max = _max
|
||||
progress = _progress
|
||||
valueFormat = this@SimpleCounterView.valueFormat
|
||||
setTitle(binding.tvSeekTitle.text)
|
||||
onChanged = {
|
||||
_progress = it
|
||||
updateValue()
|
||||
this@SimpleCounterView.onChanged?.invoke(it)
|
||||
}
|
||||
}
|
||||
|
||||
FrameLayout(ctx).apply {
|
||||
setPadding(64, 0, 64, 0)
|
||||
addView(detailSeekBar, LayoutParams(
|
||||
LayoutParams.MATCH_PARENT,
|
||||
LayoutParams.WRAP_CONTENT
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
okButton()
|
||||
cancelButton()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private fun updateValue() {
|
||||
binding.tvSeekValue.text = valueFormat?.invoke(_progress) ?: _progress.toString()
|
||||
}
|
||||
|
||||
private val startIncrementRunnable = Runnable {
|
||||
handler.post(incrementRunnable)
|
||||
}
|
||||
|
||||
private val startDecrementRunnable = Runnable {
|
||||
handler.post(decrementRunnable)
|
||||
}
|
||||
|
||||
private val incrementRunnable = object : Runnable {
|
||||
override fun run() {
|
||||
if (_progress < _max) {
|
||||
_progress++
|
||||
updateValue()
|
||||
onChanged?.invoke(_progress)
|
||||
handler.postDelayed(this, repeatInterval)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val decrementRunnable = object : Runnable {
|
||||
override fun run() {
|
||||
if (_progress > 0) {
|
||||
_progress--
|
||||
updateValue()
|
||||
onChanged?.invoke(_progress)
|
||||
handler.postDelayed(this, repeatInterval)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
handler.removeCallbacks(incrementRunnable)
|
||||
handler.removeCallbacks(decrementRunnable)
|
||||
super.onDetachedFromWindow()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,15 +3,7 @@ package io.legato.kazusa.ui.widget.text
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import io.legato.kazusa.lib.theme.Selector
|
||||
import io.legato.kazusa.lib.theme.ThemeStore
|
||||
|
||||
class TextInputLayout(context: Context, attrs: AttributeSet?) : TextInputLayout(context, attrs) {
|
||||
|
||||
init {
|
||||
if (!isInEditMode) {
|
||||
defaultHintTextColor =
|
||||
Selector.colorBuild().setDefaultColor(ThemeStore.accentColor(context)).create()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user