Android 自定义 SeekBar - 进度不跟随拇指
Android custom SeekBar - progress is not following the thumb
我想创建一个自定义的 SeekBar,但我遇到了这个问题,即在某些地方(大约 0-10 和 90-100 的进度值)进度没有跟随 SeekBar 的拇指。我相信这是因为我将 thumbOffset
设置为 0,以便拇指留在进度条内。我想制作一个 iPhone 样式的 SeekBar。
SeekBar 正在进行 0(正常):
SeekBar 正在进行 5(不正常):
SeekBar 进行中50(正常):
SeekBar 正在进行 90(不正常):
SeekBar 进行中100(正常):
根据拇指位置绘制进度时,似乎没有考虑 thumbOffset
。我尝试将 thumbOffset
更改为拇指宽度的一半,并使用不同的填充进行了各种组合,但没有解决问题。我还尝试了我在 SO 上找到的所有其他解决方案。
这是我正在使用的XML:
SeekBar 定义:
<SeekBar
android:id="@+id/scan_seekbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:max="100"
android:progress="5"
android:progressDrawable="@drawable/bg_seekbar"
android:splitTrack="false"
android:thumbOffset="0dp"
android:thumb="@drawable/seekbar_thumb" />
可绘制bg_seekbar.xml
:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<size android:height="48dp"/>
<corners android:radius="25dp"/>
<stroke android:color="@color/semiLightBlue" android:width="1dp"/>
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape android:shape="rectangle">
<corners android:radius="25dp"/>
<size android:height="48dp"/>
<stroke android:color="@color/colorAccent" android:width="1dp"/>
<solid android:color="@color/colorAccent"/>
</shape>
</clip>
</item>
</layer-list>
SeekBar 拇指 seekbar_thumb.xml
:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="rectangle">
<solid android:color="@color/colorAccent"/>
<corners android:radius="25dp"/>
<padding android:bottom="8dp" android:top="8dp" android:left="16dp" android:right="16dp" />
</shape>
</item>
<item android:drawable="@drawable/ic_swipe_white" android:gravity="center" android:height="32dp" android:width="44dp"/>
</layer-list>
还有其他人遇到过这个问题吗?
我是这样解决问题的:
首先,拇指永远不会消失。当进度为0或100时出现。当我们使用偏移时,拇指弹出。
bg_seekbar_first.xml
我们将在进度 < max / 2 时使用它
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background"
android:gravity="center_vertical|fill_horizontal">
<shape android:shape="rectangle">
<corners android:radius="24dp"/>
<size android:height="48dp" />
<stroke android:width="1dp" android:color="@color/colorAccent"/>
</shape>
</item>
<item android:id="@android:id/progress"
android:gravity="center_vertical|fill_horizontal">
<scale android:scaleWidth="100%">
<shape android:shape="rectangle"
android:tint="@color/colorAccent">
<corners android:radius="0dp"/>
<size android:height="48dp" />
<solid android:color="@color/colorAccent" />
</shape>
</scale>
</item>
</layer-list>
bg_seekbar_second.xml
我们将在进度 > max / 2
时使用它
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background"
android:gravity="center_vertical|fill_horizontal">
<shape android:shape="rectangle">
<corners android:radius="24dp"/>
<size android:height="48dp" />
<stroke android:width="1dp" android:color="@color/colorAccent"/>
</shape>
</item>
<item android:id="@android:id/progress"
android:gravity="center_vertical|fill_horizontal">
<scale android:scaleWidth="100%">
<shape android:shape="rectangle"
android:tint="@color/colorAccent">
<corners android:radius="24dp"/>
<size android:height="48dp" />
<solid android:color="@color/colorAccent" />
</shape>
</scale>
</item>
</layer-list>
seekbar_thumb.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="rectangle">
<solid android:color="@color/colorAccent"/>
<corners android:topRightRadius="24dp"
android:bottomRightRadius="24dp"/>
<padding android:bottom="8dp" android:top="8dp" android:left="16dp" android:right="16dp" />
</shape>
</item>
<item android:drawable="@android:drawable/ic_menu_close_clear_cancel" android:gravity="center" android:height="32dp" android:width="44dp"/>
</layer-list>
我改了拇指半径
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="48dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:cardCornerRadius="24dp"
android:layout_marginTop="64dp"
>
<SeekBar
android:id="@+id/scan_seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:max="100"
android:paddingStart="0dp"
android:paddingEnd="0dp"
android:progress="1"
android:progressDrawable="@drawable/bg_seekbar_first"
android:splitTrack="false"
android:thumb="@drawable/seekbar_thumb"
android:thumbOffset="0dp"
/>
</com.google.android.material.card.MaterialCardView>
我添加了一个cardView来解决这个问题:
scan_seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
if(progress < seekBar?.max!! / 2){
seekBar.progressDrawable = ContextCompat.getDrawable(context!!,R.drawable.bg_seekbar_first)
}else{
seekBar.progressDrawable = ContextCompat.getDrawable(context!!,R.drawable.bg_seekbar_second)
}
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
然后我使用这段代码(Kotlin)onProgressChanged 来解决这个问题:
结果:
希望对你有用。
您的实现依赖于 ClipDrawable 来绘制进度条。进度可绘制对象跨越进度条的整个长度,但被 ClipDrawable 缩短或剪裁。这会在进度条的左侧留下圆角,但在右侧留下方形。随着进度条的增长、赶上并超过拇指,您会看到方形的一面。
可能有几种方法可以解决这个问题,但让我们选择基于 XML 的方法。让我们用 ScaleDrawable 替换 ClipDrawable 如下:
bg_seekbar.xml
<layer-list>
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<size android:height="48dp" />
<corners android:radius="25dp" />
<stroke
android:width="1dp"
android:color="@color/semiLightBlue" />
</shape>
</item>
<item android:id="@android:id/progress">
<scale
android:scaleWidth="100%"
android:useIntrinsicSizeAsMinimum="true">
<shape android:shape="rectangle">
<corners android:radius="25dp" />
<size
android:width="50dp"
android:height="48dp" />
<stroke
android:width="1dp"
android:color="@color/colorAccent" />
<solid android:color="@color/colorAccent" />
</shape>
</scale>
</item>
</layer-list>
scaleWidth
属性告诉我们当level最大时drawable会缩放到100%。顺便说一下,useIntrinsicSizeAsMinimum
属性似乎没有记录,它指定可绘制对象的最小尺寸为其固有宽度,即 50dp x 48dp。这不完全正确,因为当级别为零时可绘制对象的宽度和高度将为零,但当级别为 1 或更高时将弹出到固有大小。
下面是进行此更改后进度条的变化。我用默认拇指来说明发生了什么:
如您所见,一旦拇指开始移动,进度条就会跳到最小尺寸并从那里变大。
所以,让我们重新介绍一下原来的拇指。这个缩略图将在开始时覆盖进度条并将跳转隐藏到最小尺寸。我们只是想覆盖那个区域,这样白色就不会显示出来。
我想创建一个自定义的 SeekBar,但我遇到了这个问题,即在某些地方(大约 0-10 和 90-100 的进度值)进度没有跟随 SeekBar 的拇指。我相信这是因为我将 thumbOffset
设置为 0,以便拇指留在进度条内。我想制作一个 iPhone 样式的 SeekBar。
SeekBar 正在进行 0(正常):
SeekBar 正在进行 5(不正常):
SeekBar 进行中50(正常):
SeekBar 正在进行 90(不正常):
SeekBar 进行中100(正常):
根据拇指位置绘制进度时,似乎没有考虑 thumbOffset
。我尝试将 thumbOffset
更改为拇指宽度的一半,并使用不同的填充进行了各种组合,但没有解决问题。我还尝试了我在 SO 上找到的所有其他解决方案。
这是我正在使用的XML:
SeekBar 定义:
<SeekBar
android:id="@+id/scan_seekbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:max="100"
android:progress="5"
android:progressDrawable="@drawable/bg_seekbar"
android:splitTrack="false"
android:thumbOffset="0dp"
android:thumb="@drawable/seekbar_thumb" />
可绘制bg_seekbar.xml
:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<size android:height="48dp"/>
<corners android:radius="25dp"/>
<stroke android:color="@color/semiLightBlue" android:width="1dp"/>
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape android:shape="rectangle">
<corners android:radius="25dp"/>
<size android:height="48dp"/>
<stroke android:color="@color/colorAccent" android:width="1dp"/>
<solid android:color="@color/colorAccent"/>
</shape>
</clip>
</item>
</layer-list>
SeekBar 拇指 seekbar_thumb.xml
:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="rectangle">
<solid android:color="@color/colorAccent"/>
<corners android:radius="25dp"/>
<padding android:bottom="8dp" android:top="8dp" android:left="16dp" android:right="16dp" />
</shape>
</item>
<item android:drawable="@drawable/ic_swipe_white" android:gravity="center" android:height="32dp" android:width="44dp"/>
</layer-list>
还有其他人遇到过这个问题吗?
我是这样解决问题的:
首先,拇指永远不会消失。当进度为0或100时出现。当我们使用偏移时,拇指弹出。
bg_seekbar_first.xml
我们将在进度 < max / 2 时使用它
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background"
android:gravity="center_vertical|fill_horizontal">
<shape android:shape="rectangle">
<corners android:radius="24dp"/>
<size android:height="48dp" />
<stroke android:width="1dp" android:color="@color/colorAccent"/>
</shape>
</item>
<item android:id="@android:id/progress"
android:gravity="center_vertical|fill_horizontal">
<scale android:scaleWidth="100%">
<shape android:shape="rectangle"
android:tint="@color/colorAccent">
<corners android:radius="0dp"/>
<size android:height="48dp" />
<solid android:color="@color/colorAccent" />
</shape>
</scale>
</item>
</layer-list>
bg_seekbar_second.xml
我们将在进度 > max / 2
时使用它<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background"
android:gravity="center_vertical|fill_horizontal">
<shape android:shape="rectangle">
<corners android:radius="24dp"/>
<size android:height="48dp" />
<stroke android:width="1dp" android:color="@color/colorAccent"/>
</shape>
</item>
<item android:id="@android:id/progress"
android:gravity="center_vertical|fill_horizontal">
<scale android:scaleWidth="100%">
<shape android:shape="rectangle"
android:tint="@color/colorAccent">
<corners android:radius="24dp"/>
<size android:height="48dp" />
<solid android:color="@color/colorAccent" />
</shape>
</scale>
</item>
</layer-list>
seekbar_thumb.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="rectangle">
<solid android:color="@color/colorAccent"/>
<corners android:topRightRadius="24dp"
android:bottomRightRadius="24dp"/>
<padding android:bottom="8dp" android:top="8dp" android:left="16dp" android:right="16dp" />
</shape>
</item>
<item android:drawable="@android:drawable/ic_menu_close_clear_cancel" android:gravity="center" android:height="32dp" android:width="44dp"/>
</layer-list>
我改了拇指半径
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="48dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:cardCornerRadius="24dp"
android:layout_marginTop="64dp"
>
<SeekBar
android:id="@+id/scan_seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:max="100"
android:paddingStart="0dp"
android:paddingEnd="0dp"
android:progress="1"
android:progressDrawable="@drawable/bg_seekbar_first"
android:splitTrack="false"
android:thumb="@drawable/seekbar_thumb"
android:thumbOffset="0dp"
/>
</com.google.android.material.card.MaterialCardView>
我添加了一个cardView来解决这个问题:
scan_seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
if(progress < seekBar?.max!! / 2){
seekBar.progressDrawable = ContextCompat.getDrawable(context!!,R.drawable.bg_seekbar_first)
}else{
seekBar.progressDrawable = ContextCompat.getDrawable(context!!,R.drawable.bg_seekbar_second)
}
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
然后我使用这段代码(Kotlin)onProgressChanged 来解决这个问题:
结果:
希望对你有用。
您的实现依赖于 ClipDrawable 来绘制进度条。进度可绘制对象跨越进度条的整个长度,但被 ClipDrawable 缩短或剪裁。这会在进度条的左侧留下圆角,但在右侧留下方形。随着进度条的增长、赶上并超过拇指,您会看到方形的一面。
可能有几种方法可以解决这个问题,但让我们选择基于 XML 的方法。让我们用 ScaleDrawable 替换 ClipDrawable 如下:
bg_seekbar.xml
<layer-list>
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<size android:height="48dp" />
<corners android:radius="25dp" />
<stroke
android:width="1dp"
android:color="@color/semiLightBlue" />
</shape>
</item>
<item android:id="@android:id/progress">
<scale
android:scaleWidth="100%"
android:useIntrinsicSizeAsMinimum="true">
<shape android:shape="rectangle">
<corners android:radius="25dp" />
<size
android:width="50dp"
android:height="48dp" />
<stroke
android:width="1dp"
android:color="@color/colorAccent" />
<solid android:color="@color/colorAccent" />
</shape>
</scale>
</item>
</layer-list>
scaleWidth
属性告诉我们当level最大时drawable会缩放到100%。顺便说一下,useIntrinsicSizeAsMinimum
属性似乎没有记录,它指定可绘制对象的最小尺寸为其固有宽度,即 50dp x 48dp。这不完全正确,因为当级别为零时可绘制对象的宽度和高度将为零,但当级别为 1 或更高时将弹出到固有大小。
下面是进行此更改后进度条的变化。我用默认拇指来说明发生了什么:
如您所见,一旦拇指开始移动,进度条就会跳到最小尺寸并从那里变大。
所以,让我们重新介绍一下原来的拇指。这个缩略图将在开始时覆盖进度条并将跳转隐藏到最小尺寸。我们只是想覆盖那个区域,这样白色就不会显示出来。