目录
- 1、前言
- 2、ProgressBar
- 3、SeekBar
- 4、结尾
1、前言
最近在开发中,同事对于android.widget下的控件一知半解,又恰好那天用到了Seekbar,想了想,那就从Seekbar's father ProgressBar 来说说android.widget下的常用控件和常用用法吧。后面也会根据这些控件来进行仿写、扩展,做一些高度自定义的View啦。如果写的不好,或者有错误之处,恳请在评论、私信、邮箱指出,万分感谢🙏
2、ProgressBar
A user interface element that indicates the progress of an operation.
使用很简单,看看一些基本的属性
android:max:进度条的最大值
android:progress:进度条已完成进度值
android:progressDrawable:设置轨道对应的Drawable对象
android:indeterminate:如果设置成true,则进度条不精确显示进度(会一直进行动画)
android:indeterminateDrawable:设置不显示进度的进度条的Drawable对象
android:indeterminateDuration:设置不精确显示进度的持续时间
android:secondaryProgress:二级进度条(使用场景不多)
直接在布局中使用即可
<ProgressBar | |
style="@android:style/Widget.ProgressBar.Small" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_marginTop="dp" /> | |
<ProgressBar | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_marginTop="dp" /> | |
<ProgressBar | |
style="@android:style/Widget.ProgressBar.Large" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_marginTop="dp" /> | |
<ProgressBar | |
android:id="@+id/sb_no_beautiful" | |
style="@android:style/Widget.ProgressBar.Horizontal" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_marginTop="dp" | |
android:max="" | |
android:progress="" | |
android:secondaryProgress="" /> | |
<ProgressBar | |
android:id="@+id/sb_no_beautiful" | |
style="@android:style/Widget.Holo.ProgressBar.Horizontal" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_marginTop="dp" | |
android:indeterminate="true" | |
android:max="" | |
android:progress="" | |
android:secondaryProgress="" /> |
分别就对应以下图片咯
但是这种样式,不得不怀疑Google之前的审美,肯定是不满意的,怎么换样式呢。
看看XML文件,很容易发现,这几个ProgressBar的差异是因为style引起的,随手点开一个@android:style/Widget.ProgressBar.Horizontal 看看。
<style name="Widget.ProgressBar.Horizontal"> | |
<item name="indeterminateOnly">false</item> | |
<item name="progressDrawable">@drawable/progress_horizontal</item> | |
<item name="indeterminateDrawable">@drawable/progress_indeterminate_horizontal</item> | |
<item name="minHeight">dip</item> | |
<item name="maxHeight">dip</item> | |
<item name="mirrorForRtl">true</item> | |
</style> |
很好,估摸着样式就出在progressDrawable/indeterminateDrawable上面,看看 @drawable/progress_horizontal 里面
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> | |
<item android:id="@android:id/background"> | |
<shape> | |
<corners android:radius="dip" /> | |
<gradient | |
android:startColor="#ffd9e9d" | |
android:centerColor="#ffa5d5a" | |
android:centerY=".75" | |
android:endColor="#ff" | |
android:angle=""/> | |
</shape> | |
</item> | |
<item android:id="@android:id/secondaryProgress"> | |
<clip> | |
<shape> | |
<corners android:radius="dip" /> | |
<gradient | |
android:startColor="#ffd300" | |
android:centerColor="#ffb600" | |
android:centerY=".75" | |
android:endColor="#affcb00" | |
android:angle=""/> | |
</shape> | |
</clip> | |
</item> | |
<item android:id="@android:id/progress"> | |
<clip> | |
<shape> | |
<corners android:radius="dip" /> | |
<gradient | |
android:startColor="#ffffd" | |
android:centerColor="#ffffb" | |
android:centerY=".75" | |
android:endColor="#ffffcb" | |
android:angle=""/> | |
</shape> | |
</clip> | |
</item> | |
</layer-list> |
一个样式文件,分别操控了background/secondaryProgress/progress,这样我们很容易推测出
再看看 @drawable/progress_indeterminate_horizontal
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> | |
<item android:drawable="@drawable/progressbar_indeterminate" android:duration="200" /> | |
<item android:drawable="@drawable/progressbar_indeterminate" android:duration="200" /> | |
<item android:drawable="@drawable/progressbar_indeterminate" android:duration="200" /> | |
</animation-list> |
显而易见,这是indeterminate模式下的样式啊,那我们仿写一个不同样式,就很简单了,动手。
styles.xml
<style name="ProgressBar_Beautiful" > | |
<item name="android:indeterminateOnly">false</item> | |
<item name="android:progressDrawable">@drawable/progress_horizontal_</item> | |
<item name="android:indeterminateDrawable">@drawable/progress_indeterminate_beautiful</item> | |
<item name="android:mirrorForRtl">true</item> | |
</style> |
progress_horizontal_1.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> | |
<item android:id="@android:id/background"> | |
<shape> | |
<corners android:radius="dp" /> | |
<solid android:color="#FFFF0F0"/> | |
</shape> | |
</item> | |
<item android:id="@android:id/secondaryProgress"> | |
<clip> | |
<shape> | |
<corners android:radius="dp" /> | |
<solid android:color="#FFCEC87"/> | |
</shape> | |
</clip> | |
</item> | |
<item android:id="@android:id/progress"> | |
<clip> | |
<shape> | |
<corners android:radius="dp" /> | |
<solid android:color="#FFAE05B"/> | |
</shape> | |
</clip> | |
</item> | |
</layer-list> |
progress_indeterminate_beautiful.xml
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" | |
android:oneshot="false"> | |
<item android:drawable="@drawable/bg_progress_" android:duration="200" /> | |
<item android:drawable="@drawable/bg_progress_" android:duration="200" /> | |
<item android:drawable="@drawable/bg_progress_" android:duration="200" /> | |
<item android:drawable="@drawable/bg_progress_" android:duration="200" /> | |
</animation-list> |
吭呲吭呲就写出来了,看看效果
换了个颜色,加了个圆角/ 换了个图片,还行。
我没有去再写环形的ProgressBar了,因为它就是个一个图,疯狂的在旋转。
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android" | |
android:drawable="@drawable/spinner_white_" | |
android:pivotX="%" | |
android:pivotY="%" | |
android:framesCount="" | |
android:frameDuration="" /> |
还有一些属性我就不赘述了。你可以根据官方的样式,修一修、改一改,就可以满足一些基本的需求了。
用起来就这么简单,就是因为太简单,更复杂的功能就不是ProgressBar能直接实现的了。比如带个滑块?
3、SeekBar
好吧,ProgressBar的一个子类,也在android.widget下,因为是直接继承,而且就加了个滑块相关的代码,实际上它也非常简单,然我们来看看
<SeekBar | |
android:id="@+id/sb_" | |
style="@style/ProgressBar_Beautiful" | |
android:layout_width="match_parent" | |
android:layout_height="dp" | |
android:layout_marginVertical="dp" | |
android:thumbOffset="dp" | |
android:max="" | |
android:progress="" | |
android:secondaryProgress="" | |
android:splitTrack="false" | |
android:thumb="@drawable/icon_seekbar_thum" /> | |
<SeekBar | |
android:id="@+id/sb_" | |
style="@style/ProgressBar_Beautiful" | |
android:layout_width="match_parent" | |
android:layout_height="dp" | |
android:layout_marginVertical="dp" | |
android:max="" | |
android:progress="" | |
android:secondaryProgress="" | |
android:thumb="@drawable/icon_seekbar_thum" /> | |
<SeekBar | |
android:id="@+id/sb_" | |
style="@style/ProgressBar_Beautiful" | |
android:layout_width="match_parent" | |
android:layout_height="dp" | |
android:layout_marginVertical="dp" | |
android:max="" | |
android:progress="" | |
android:secondaryProgress="" | |
android:splitTrack="false" | |
android:thumb="@drawable/icon_seekbar_thum" /> | |
<SeekBar | |
android:id="@+id/sb_" | |
style="@style/ProgressBar_Beautiful" | |
android:layout_width="match_parent" | |
android:layout_height="dp" | |
android:layout_marginVertical="dp" | |
android:thumbOffset="dp" | |
android:max="" | |
android:progress="" | |
android:secondaryProgress="" | |
android:splitTrack="false" | |
android:thumb="@drawable/icon_seekbar_thum" /> | |
<SeekBar | |
android:id="@+id/sb_" | |
style="@style/ProgressBar_Beautiful" | |
android:layout_width="match_parent" | |
android:layout_height="dp" | |
android:layout_marginVertical="dp" | |
android:max="" | |
android:paddingHorizontal="dp" | |
android:progress="" | |
android:secondaryProgress="" | |
android:thumb="@drawable/icon_seekbar_thum" /> | |
<SeekBar | |
android:id="@+id/sb_" | |
style="@style/ProgressBar_Beautiful" | |
android:layout_width="match_parent" | |
android:layout_height="dp" | |
android:layout_marginVertical="dp" | |
android:max="" | |
android:progress="" | |
android:secondaryProgress="" | |
android:thumb="@null" /> |
样式就在下面了
因为Seekbar相较而言就多了个thumb(就是那个滑块),所以就着重说一下滑块,其他的就一笔带过咯。
主要了解的是如何设置自己的thumb和thumb的各种问题
android:thumb="@drawable/icon_seekbar_thum"
设置就这么thumb简单,一个drawable文件解决,我这里对应的是单一图片,不过Google的是带有多种状态的thumb,我们来看看官方是如何实现的
<selector xmlns:android="http://schemas.android.com/apk/res/android" | |
android:constantSize="true"> | |
<item android:state_enabled="false" android:state_pressed="true"> | |
<bitmap android:src="@drawable/abc_scrubber_control_off_mtrl_alpha"android:gravity="center"/> | |
</item> | |
<item android:state_enabled="false"> | |
<bitmap android:src="@drawable/abc_scrubber_control_off_mtrl_alpha"android:gravity="center"/> | |
</item> | |
<item android:state_pressed="true"> | |
<bitmap android:src="@drawable/abc_scrubber_control_to_pressed_mtrl_" android:gravity="center"/> | |
</item> | |
<item> | |
<bitmap android:src="@drawable/abc_scrubber_control_to_pressed_mtrl_"android:gravity="center"/> | |
</item> | |
</selector> |
引用一个drawable,也是一个熟知的selector组,通过对应的item,我们就可以实现在不同的状态下显示不同的thumb了,具体的样式我就不写了,再说ProgressBar的样式的时候也是有类似的操作的
不过你可能发现了,其实这几个样式看起来都差不多,是因为都是我使用Seekbar遇到的问题以及解决方法,我们细说
(1) 自定义的thumb的背景会裁剪出一个正方形,这对于不规则图形来讲是非常难看的
很简单一行
android:splitTrack="false"
修复0。0
(2)thumb的中心点对齐bar的边界,所以thumb是允许超出进度条一点的。有时候我们不需要
很简单一行
android:thumbOffset="1dp"
修复0,0
(3) 你可能发现就算没有写margin和padding,seekbar也不会占满父布局的,是因为它自带padding,所以如果需要去掉
很简单一行
android:paddingHorizontal="0dp"
修复0>0
(4)最后一个,SeekBar但是不想要滑块!为什么不用ProgressBar呢?没别的就是头铁!
很简单一行
android:thumb="@null"
修复0」0
但是要注意的是,此时Seekbar还是能点击的!所以需要把点击事件拦截掉
sb.setOnTouchListener { _, _ -> true }
真的修复0[]0
好了好了,thumb的监听事件还没说呢
sb.setOnSeekBarChangeListener(object : OnSeekBarChangeListener { | |
override fun onProgressChanged(p: SeekBar?, p1: Int, p2: Boolean) { | |
//进度发生改变时会触发 | |
} | |
override fun onStartTrackingTouch(p: SeekBar?) { | |
//按住SeekBar时会触发 | |
} | |
override fun onStopTrackingTouch(p: SeekBar?) { | |
//放开SeekBar时触发 | |
} | |
}) |
没啦,Seekbar就这么多。
还有一个,放在下次讲吧
对了,如果你感觉你的ProgressBar不够流畅,可以用以下这个
bar.setProgress(progress, true)
4、结尾
更多复杂的进度条需求,靠widget的控件,肯定是难以实现的,我们接下来会讲述RatingBar,以及继承ProgressBar,做更多好看的进度条!