SeekBar的样式修改及分析

来源:互联网 发布:手机淘宝人工客服 编辑:程序博客网 时间:2024/06/11 08:02

今天在看视频的时候感觉视频底部的SeekBar样式还不错,所以就亲手实践改了一下系统默认的样式。

这里我先做了一个SeekBar的结构分析图:


这里写图片描述


先看一下效果,不是很炫酷,上面的是我的,下面的是系统原生的样式,没有人家的那么迷你,只想让你看的更清楚


这里写图片描述

这里写图片描述

首先我去系统的values.xml搜索SeekBar,搜索结果如下


<style name="Base.Widget.AppCompat.SeekBar" parent="android:Widget">        <item name="android:indeterminateOnly">false</item>        <item name="android:progressDrawable">@drawable/abc_seekbar_track_material</item>        <item name="android:indeterminateDrawable">@drawable/abc_seekbar_track_material</item>        <item name="android:thumb">@drawable/abc_seekbar_thumb_material</item>        <item name="android:focusable">true</item>        <item name="android:paddingLeft">16dip</item>        <item name="android:paddingRight">16dip</item>    </style>

方式一


我们只要修改android:progressDrawable和android:thumb这个就可以达到自己想要的效果,所以将这两个属性Copy出来,在我们自己的styles.xml中创建如下style即可:

<style name="jrt_seekbar_style" parent="Base.Widget.AppCompat.SeekBar">        <item name="android:progressDrawable">@drawable/my_seekbar_style</item>        <item name="android:thumb">@drawable/seekbar_thumb</item>    </style>

接下来开启照猫画虎模式


my_seekbar_style这个drawable的写法我们去参靠系统的abc_seekbar_track_material.xml,直接一个copy在我们的drawable目录下,然后改成我们自己的文件名字,如:my_seekbar_style.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"        android:drawable="@drawable/seekbar_bg"/>    <item android:id="@android:id/secondaryProgress">        <scale android:scaleWidth="100%">            <selector>                <item android:state_enabled="false">                    <color android:color="@android:color/transparent"/>                </item>                <item android:drawable="@drawable/seekbar_progress_2"/>            </selector>        </scale>    </item>    <item android:id="@android:id/progress">        <scale android:scaleWidth="100%">            <selector>                <item android:state_enabled="false">                    <color android:color="@android:color/transparent"/>                </item>                <item android:drawable="@drawable/seekbar_progress"/>            </selector>        </scale>    </item></layer-list>

其实这些代码都是google工程师写好的,我们只要把对应的drawable换成我们自己的即可。在layout应用的时候直接给Seekbar设置style属性即可;

<SeekBar        android:id="@+id/seekBar"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_alignParentTop="true"        android:layout_alignParentRight="true"        android:layout_alignParentEnd="true"        android:layout_marginTop="140dp"        style="@style/jrt_seekbar_style"        />

方式二


我们不用在styles.xml中设置属性,将my_seekbar_style.xml和seekbar_thumb两个资源准备好了直接在layout中使用。如下:

<SeekBar        android:id="@+id/myseekBar"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_alignParentTop="true"        android:layout_alignParentRight="true"        android:layout_alignParentEnd="true"        android:progress="30"        android:thumb="@drawable/seekbar_thumb"        android:progressDrawable="@drawable/my_seekbar_style"         />

做过开发的都知道这两种使用方式的要根据具体的场景而定,主要取决与你的SeekBar使用频率,如果只用一次就用方式二,如果多次,并且全局都使用同样的Seekbar那就用方式一,这样更体现了封装抽取,便于项目的维护和管理。其实应该还有方式三,在java代码中设置其属性。接下来说说踩多的坑,程序员都是踩着坑成长的。



my_seekbar_style.xml在写的时候一定要按系统android:id的顺序来,不要随便改变item的顺序,必须是background->secondaryProgress->progress;我一开始没有copy系统代码,直接手写就掉坑里了把id顺序写成background->-progress>secondaryProgress;结果就成这样了,如图:

蓝色本来是progress应该随拖动的按钮变化而变化的,结果成了secondaryProgress缓冲进度了,刚好两个交换位置了,层级关系乱了。如果顺序写成secondaryProgress->progress->background那就更抽象了,直接把背景放到最顶层了,其他都被这挡了,如下图:
这里写图片描述

这个错误犯得好,让我明白了SeekBar是完全按照background->secondaryProgress->progress这个从低往高的层级关系显示UI的

最后来看一下SeekBar的源码


这里写图片描述

由上面的类关系集成图可以看出,SeekBar继承 AbsSeekBar,所以SeekBar本身没做什么工作,我们用到的就是它的一个内部接口回调OnSeekBarChangeListener,通过这个回调操作SeekBar不同状态下的操作。

public interface OnSeekBarChangeListener {        /**         * Notification that the progress level has changed. Clients can use the fromUser parameter         * to distinguish user-initiated changes from those that occurred programmatically.         *         * @param seekBar The SeekBar whose progress has changed         * @param progress The current progress level. This will be in the range 0..max where max         *        was set by {@link ProgressBar#setMax(int)}. (The default value for max is 100.)         * @param fromUser True if the progress change was initiated by the user.         */        void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser);        /**         * Notification that the user has started a touch gesture. Clients may want to use this         * to disable advancing the seekbar.         * @param seekBar The SeekBar in which the touch gesture began         */        void onStartTrackingTouch(SeekBar seekBar);        /**         * Notification that the user has finished a touch gesture. Clients may want to use this         * to re-enable advancing the seekbar.         * @param seekBar The SeekBar in which the touch gesture began         */        void onStopTrackingTouch(SeekBar seekBar);    }

再看看AbsSeekBar继承于ProgressBar,通过下面AbsSeekBar源码中drawThumb(canvas)可以看出AbsSeekBar是在ProgressBar基础上多绘制了一个thumb,也就多了一个手指拖动进度的功能。所以SeekBar本身没有参与UI样式的修改工作,我们修改的progressDrawable是ProgressBar的,修改的thumb是AbsSeekBar的。还有一个就是SeekBar的子类AppCompatSeekBar,AppCompatSeekBar内部封装了一个AppCompatSeekBarHelper就是便于我们操作的,具体自己看源码。

@Override    protected synchronized void onDraw(Canvas canvas) {        super.onDraw(canvas);        drawThumb(canvas);    }    @Override    void drawTrack(Canvas canvas) {        final Drawable thumbDrawable = mThumb;        if (thumbDrawable != null && mSplitTrack) {            final Insets insets = thumbDrawable.getOpticalInsets();            final Rect tempRect = mTempRect;            thumbDrawable.copyBounds(tempRect);            tempRect.offset(mPaddingLeft - mThumbOffset, mPaddingTop);            tempRect.left += insets.left;            tempRect.right -= insets.right;            final int saveCount = canvas.save();            canvas.clipRect(tempRect, Op.DIFFERENCE);            super.drawTrack(canvas);            drawTickMarks(canvas);            canvas.restoreToCount(saveCount);        } else {            super.drawTrack(canvas);            drawTickMarks(canvas);        }    }

总结

最后那部分不是在做源码解析,我只是发表个人观点,如果有什么不对的可以,在下面留言,相互学习。知识在于探索,更在于创新。还是老话,举一反三。

2 0
原创粉丝点击