為了更好的滿足日常開發(fā)中對Slider控件的各種需要掺栅,以下我們來看下基于nifty-slider來定制我們所需的各種功能及交互效果
一、 功能支持
支持滑動條起始值結(jié)束值的自定義
支持滑動條指定步長以實現(xiàn)類似刻度的功能
支持對滑塊的自定義以添加光環(huán)效果纳猪、滑塊形狀氧卧,滑塊投影、滑塊邊框氏堤、滑塊內(nèi)文本等定義
支持使用任意圖像對滑塊進行修改
支持對滑軌的起始結(jié)束位置添加圖標(biāo)或文本
滑塊支持使用Lottie Animation
支持滑動過程對滑塊沙绝、滑軌的狀態(tài)顏色高度等屬性添加交互動畫
支持對控件的各個零部件進行深度的定制
二、 具體效果實現(xiàn)
1. Material Design 3 樣式
此樣式只需要定義好滑塊鼠锈、滑軌的狀態(tài)顏色即可
<com.litao.slider.NiftySlider
android:id="@+id/nifty_slider"
android:layout_width="match_parent"
android:layout_height="148dp"
android:padding="16dp"
android:value="50"
android:valueFrom="0"
android:valueTo="100"
app:trackColor="@color/m3_demo_track_color"
app:trackColorInactive="@color/m3_demo_track_inactive_color"
app:thumbColor="@color/m3_demo_thumb_color"
app:thumbShadowColor="@color/white"
app:haloColor="@color/m3_demo_halo_color"/>
2. 微信閱讀中使用的Slider樣式
此樣式我們需要使用到一個自定義效果ITEffect
,定義好相關(guān)屬性后闪檬,然后給我們的Slider添加此效果即可
val customEffect = ITEffect(this).apply {
startText = "大"
endText = "小"
startTextSize = 12f.dp
endTextSize = 12f.dp
startTintList = ColorStateList.valueOf(iconTintColor)
endTintList = ColorStateList.valueOf(iconTintColor)
startPadding = 12.dp
endPadding = 12.dp
}
niftySlider3.apply {
effect = customEffect
setTrackTintList(ColorStateList.valueOf(activeTrackColor))
setTrackInactiveTintList(ColorStateList.valueOf(inactiveTrackColor))
}
要記得添加thumbWithinTrackBounds=ture
屬性,以保證我們的滑塊在滑軌內(nèi)部购笆,默認(rèn)情況是以滑塊中心為基準(zhǔn)點粗悯,滑動到起始和結(jié)束位置時滑塊會超出滑軌
<com.litao.slider.NiftySlider
...
android:value="22"
android:valueFrom="16"
android:valueTo="28"
app:trackHeight="36dp"
app:thumbRadius="18dp"
app:thumbTextSize="12sp"
app:thumbText="邊距"
android:hapticFeedbackEnabled="true"
app:thumbTextColor="@color/we_read_theme_color"
app:thumbColor="@color/we_read_thumb_color"
android:stepSize="1"
app:thumbWithinTrackBounds="true"
app:enableDrawHalo="false" />
3. 自定義滑塊樣式
這個只需要直接指定我們想要的圖像Res ID即可,像下面這樣,比較容易吧同欠。
setThumbCustomDrawable(R.drawable.custom_thumb)
如果普通的圖像滿足不了的話我們還可以自己去實現(xiàn)Drawable來完成有著更為豐富的交互和效果的滑塊样傍,像下面我們完成了一個嗶哩嗶哩視頻拖動條的效果,和上面相同只需要只需要調(diào)用setThumbCustomDrawable(myCustomDrawable)
即可,可以看看到滑軌在滑動開始和結(jié)束后還有一個動畫效果铺遂,后面我們再詳細(xì)說明這部分
可以在 這里查看 BiliBiliDrawable
的完整代碼
4. 顏色選擇器
我們可以使用ColorPickEffect
來實現(xiàn)一個顏色選擇器衫哥,所選擇的顏色會在OnColorValueChangeListener
回調(diào)中返回,然后對所需要的位置直接修改即可襟锐,如果默認(rèn)的色值無法滿足也可以調(diào)用ColorPickEffect.updateColors
方法來修改為我們想要的顏色數(shù)組
val colorEffect = ColorPickEffect(niftySlider)
colorEffect.colorValueChangeListener =
ColorPickEffect.OnColorValueChangeListener { slider, color, fromUser ->
//color changed
colorText.setBackgroundColor(color)
colorText.text = Utils.toHexColorString(color)
niftySlider.setThumbShadowColor(color)
niftySlider.setThumbStrokeColor(ColorStateList.valueOf(color))
}
5. 抖音視頻滑動條樣式
可以看到抖音的滑動條中是在滑動開始和結(jié)束有一個很自然的動畫的過度炕檩,這個效果我們也可以借助AnimationEffect
來完成,定義好我們自己的動畫對象,添加開始與結(jié)束的相關(guān)屬性配置即可笛质。在上面提到的嗶哩嗶哩的效果中我們也同時結(jié)合使用了該效果泉沾。
val animEffect = AnimationEffect(niftySlider).apply {
srcTrackHeight = 3.dp
srcThumbHeight = 6.dp
srcThumbWidth = 6.dp
srcThumbRadius = 3.dp
srcThumbColor = thumbColor
srcTrackColor = thumbTrackColor
srcInactiveTrackColor = thumbInactiveColor
targetTrackHeight = 12.dp
targetThumbHeight = 16.dp
targetThumbWidth = 8.dp
targetThumbRadius = 5.dp
targetThumbColor = Color.WHITE
targetTrackColor = ColorUtils.setAlphaComponent(Color.WHITE, 0xDD)
targetInactiveTrackColor = ColorUtils.setAlphaComponent(Color.WHITE, 0x33)
animationListener = object : AnimationEffect.OnAnimationChangeListener {
override fun onEnd(slider: NiftySlider) {
//do something on animation end
}
}
setInterpolator(FastOutLinearInInterpolator())
}
三、 定義我們自己的交互效果
從項目中可以看到包含了兩個模塊
-
nifty-slider
: 滑動條的基礎(chǔ)功能 -
nifty-slider-effect
: 用于深度定制滑動條妇押、增強交互效果
- 使用
nifty-slider-effect
lib 繼承 BaseEffect - 實現(xiàn)相關(guān)方法跷究,開始我們的自定義之旅
/** Called when a slider's touch event is being started */
fun onStartTacking(slider: T)
/** Called when a slider's touch event is being stopped */
fun onStopTacking(slider: T)
/** Called when the value of the slider changes */
fun onValueChanged(slider: T, value: Float, fromUser: Boolean)
/** Called before draw inactive track . Return true if the interrupt default draw*/
fun dispatchDrawInactiveTrackBefore(slider: T, canvas: Canvas, trackRect: RectF, yCenter: Float): Boolean
/** Called after draw inactive track */
fun drawInactiveTrackAfter(slider: T, canvas: Canvas, trackRect: RectF, yCenter: Float)
/** Called before draw active track . Return true if the interrupt default draw*/
fun dispatchDrawTrackBefore(slider: T, canvas: Canvas, trackRect: RectF, yCenter: Float): Boolean
/** Called after draw active track */
fun drawTrackAfter(slider: T, canvas: Canvas, trackRect: RectF, yCenter: Float)
/** Called before draw thumb drawable . Return true if the interrupt default draw*/
fun dispatchDrawThumbBefore(slider: T, canvas: Canvas, cx: Float, cy: Float): Boolean
/** Called after draw thumb drawable */
fun drawThumbAfter(slider: T, canvas: Canvas, cx: Float, cy: Float)
- 挑選合適的方法,例如
dispatchDrawTrackBefore
是在繪制激活狀態(tài)的滑軌之前調(diào)用敲霍,返回true
表示由我們來接管繪制俊马,需要控件再進行此部件的繪制 - 下面我們結(jié)合Lottie Animation來定制一個有動畫效果的滑塊,首先引入
lottie
最新版本肩杈,下面我們需要用到其中的LottieDrawable
implementation 'com.airbnb.android:lottie:6.0.0'
5.完整的效果代碼
class LottieAnimationEffect(private val slider: NiftySlider) : BaseEffect() {
var animDrawable: LottieDrawable
private var isAutoLoopMode = false
init {
slider.valueFrom = 0f
slider.valueTo = 1f
animDrawable = LottieDrawable().apply {
enableMergePathsForKitKatAndAbove(true)
callback = slider
repeatCount = LottieDrawable.INFINITE
setMinAndMaxProgress(0f,1f)
addAnimatorUpdateListener {
slider.invalidate()
}
progress = slider.value
}
slider.setThumbCustomDrawable(animDrawable)
}
override fun onValueChanged(slider: NiftySlider, value: Float, fromUser: Boolean) {
super.onValueChanged(slider, value, fromUser)
if (!isAutoLoopMode) {
animDrawable.progress = value
}
}
fun setAnimation(assetName: String) {
val result: LottieResult<LottieComposition> =
LottieCompositionFactory.fromAssetSync(slider.context.applicationContext, assetName)
animDrawable.composition = result.value
}
fun setAutoLoopMode(isLoop: Boolean){
if (isLoop == isAutoLoopMode){
return
}
this.isAutoLoopMode = isLoop
if (isLoop){
animDrawable.start()
}else{
animDrawable.stop()
animDrawable.progress = slider.value
}
}
}
6.這樣就完成了一個簡單的自定義效果柴我,我們來看下效果。
四扩然、 Demo 下載
五艘儒、 結(jié)束
希望使用這一個控件能夠滿足你項目中對slider的所有要求,滑動浮窗夫偶、區(qū)間選擇等功能還在開發(fā)中界睁,希望后續(xù)能夠提供更全面的更細(xì)致的方法及回調(diào)來滿足你的定制需求。我也會不斷的添加各種交互效果盡量涵蓋當(dāng)前所有主流應(yīng)用中的效果兵拢。
如當(dāng)前無法滿足你的需求可以提交 Issues
如你自定義了一個很棒的效果也可以提交PR
如果覺得有幫助就送上一個Star
吧,為作者提供更多動力