android系统锁屏详解【android锁屏解析二】

时间:2022-06-05 17:19:32
 谷歌的代码写的确实不错,我很幸运,一开始接触代码就赶上了谷歌这个开源的系统,让我的视野开阔了很多,也让我看到了优秀的代码工程师写到的代码。心怀感恩之心

                                                                                                                          ----题记

       我的有篇文章说了这个锁屏,但当时写的有点匆忙,没有细说。

                      AndroidICS4.0---->LockScreen锁屏流程【Android源码解析九】

        好了,开始正题,系统原声的锁屏界面,先来看一张图片:

                           android系统锁屏详解【android锁屏解析二】

再上一张选中中间解锁的图片:
                           android系统锁屏详解【android锁屏解析二】

这个圆形的解锁界面,左边是照相机,右边是解锁。下面我们来说说这个功能的具体实现,以及怎么修改成为上下左右四个方向的解锁界面。

Step1:先看LockScreen.java这个类加载的布局

inflater.inflate(R.layout.keyguard_screen_tab_unlock, this, true);

然后看对应的布局文件:

<com.android.internal.widget.multiwaveview.MultiWaveView            android:id="@+id/unlock_widget"            android:orientation="horizontal"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:layout_alignParentBottom="true"            android:targetDrawables="@array/lockscreen_targets_with_camera"            android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera"            android:directionDescriptions="@array/lockscreen_direction_descriptions"            android:handleDrawable="@drawable/ic_lockscreen_handle"            android:waveDrawable="@drawable/ic_lockscreen_outerring"            android:outerRadius="@dimen/multiwaveview_target_placement_radius"            android:snapMargin="@dimen/multiwaveview_snap_margin"            android:hitRadius="@dimen/multiwaveview_hit_radius"            android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right"            android:horizontalOffset="0dip"            android:verticalOffset="60dip"            android:feedbackCount="3"            android:vibrationDuration="20"            />

下面我们来细细研究这些属性的含义:

        空行上面的属性都是android常用的一些属性,相信不用我说了;

   (1) android:targetDrawables="@array/lockscreen_targets_with_camera"

        这个属性表示目标的图标有几个,android默认是2个,不过我们可以修改这个array的值,我们看看这个值

         

<array name="lockscreen_targets_with_camera">        <item>@drawable/ic_lockscreen_unlock</item>        <item>@null</item>        <item>@drawable/ic_lockscreen_camera</item>        <item>@null</item>    </array>
        我相信你这样表示就应该明白该怎么修改了,这四个item分别对应圆圈的位置是右,上,左,下。

        想加几个图片,这个完全取决你自己,像小米的锁屏是四个,就是修改的这里。其实也没什么的,so easy!


  (2) android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera"

        这个属性是对应的描述语言,

<array name="lockscreen_target_descriptions_with_camera">        <item>@string/description_target_unlock</item>        <item>@null</item>        <item>@string/description_target_camera</item>        <item>@null</item>    </array>
        你要是修改(1)的话,你也就相应的修改这些字符串就可以了。这个没什么可说的了。


  (3) android:directionDescriptions="@array/lockscreen_direction_descriptions"

       这个属性和(2)差不多,

<array name="lockscreen_direction_descriptions">        <item>@string/description_direction_right</item>        <item>@null</item>        <item>@string/description_direction_left</item>        <item>@null</item>    </array>
       这个表示的含义就是:对应四个位置,右,上,左,下这四个位置,提示语言:向哪个方向滑的问题。


  (4) android:handleDrawable="@drawable/ic_lockscreen_handle"
       这个属性对应的就是中间的那个解锁的图标,对应2张图片,一张选中的图片,一张默认没有选中的图片。

<selector xmlns:android="http://schemas.android.com/apk/res/android">    <item        android:state_enabled="true"        android:state_active="false"        android:state_focused="false"        android:drawable="@drawable/ic_lockscreen_handle_normal" />    <item        android:state_enabled="true"        android:state_active="true"        android:state_focused="false"        android:drawable="@drawable/ic_lockscreen_handle_pressed" /></selector>

  (5) android:waveDrawable="@drawable/ic_lockscreen_outerring"

       这个属性对应的就是最外面的圆圈,是用shape属性画出来的。如:

<shape xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="oval"    >    <size android:height="@dimen/keyguard_lockscreen_outerring_diameter" android:width="@dimen/keyguard_lockscreen_outerring_diameter" />    <solid android:color="#00000000" />    <stroke android:color="#1affffff" android:width="2dp" /></shape>
         以上的这些值都可以修改的。


  (6) android:outerRadius="@dimen/multiwaveview_target_placement_radius"

       这个属性表示默认圆的半径的大小;

<!-- Default target placement radius for MultiWaveView -->    <dimen name="multiwaveview_target_placement_radius">135dip</dimen>

  (7) android:snapMargin="@dimen/multiwaveview_snap_margin"

       这个属性是默认超越MultiWaveView捕捉到目标半径距离  

<!-- Default distance beyond which MultiWaveView snaps to the target radius -->    <dimen name="multiwaveview_snap_margin">20dip</dimen>

  (8) android:hitRadius="@dimen/multiwaveview_hit_radius"

      这个属性表示:每个单元目标预设距离,MultiWaveView认为选中

<!-- Default distance from each snap target that MultiWaveView considers a "hit" -->    <dimen name="multiwaveview_hit_radius">60dip</dimen>

  (9)android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right"

     这个属性表示:动态画的波纹的图片,这个属性共有四个,分别为,左,上,右,下四个方位的。

    

  (10) android:horizontalOffset="0dip"
         android:verticalOffset="60dip"

        这2个属性表示:距离圆圈水平和垂直的距离。你就明白为什么圆的下方少一块的原因了。


  (11) android:feedbackCount="3"

         表示:反馈数量3个;


  (12) android:vibrationDuration="20"

          表示:默认震动的时间,20毫秒;


更多属性请参考:core/res/res/values/attrs.xml中

<!-- =============================== -->    <!-- MultiWaveView class attributes -->    <!-- =============================== -->    <eat-comment />    <declare-styleable name="MultiWaveView">        <!-- Reference to an array resource that be shown as targets around a circle. -->        <attr name="targetDrawables" format="reference"/>        <!-- Reference to an array resource that be used as description for the targets around the circle. -->        <attr name="targetDescriptions" format="reference"/>        <!-- Reference to an array resource that be used to announce the directions with targets around the circle. -->        <attr name="directionDescriptions" format="reference"/>        <!-- Sets a drawable as the drag center. -->        <attr name="handleDrawable" format="reference" />        <!-- Drawable to use for chevron animation on the left. May be null. -->        <attr name="leftChevronDrawable" format="reference" />        <!-- Drawable to use for chevron animation on the right. May be null. -->        <attr name="rightChevronDrawable" format="reference" />        <!-- Drawable to use for chevron animation on the top. May be null. -->        <attr name="topChevronDrawable" format="reference" />        <!-- Drawable to use for chevron animation on the bottom. May be null. -->        <attr name="bottomChevronDrawable" format="reference" />        <!-- Drawable to use for wave ripple animation. -->        <attr name="waveDrawable" format="reference" />        <!-- Outer radius of target circle. Icons will be drawn on this circle. -->        <attr name="outerRadius" format="dimension" />        <!-- Size of target radius. Points within this distance of target center is a "hit". -->        <attr name="hitRadius" format="dimension" />        <!-- Tactile feedback duration for actions. Set to '0' for no vibration. -->        <attr name="vibrationDuration" format="integer"/>        <!-- How close we need to be before snapping to a target. -->        <attr name="snapMargin" format="dimension" />        <!-- Number of waves/chevrons to show in animation. -->        <attr name="feedbackCount" format="integer" />        <!-- Used to shift center of pattern vertically. -->        <attr name="verticalOffset" format="dimension" />        <!-- Used to shift center of pattern horizontally. -->        <attr name="horizontalOffset" format="dimension" />    </declare-styleable>
这些属性能帮助你自定义自己的锁屏,如果不够的话,你也可以自己添加,然后在MultiWaveView.java中添加自己的方法或属性。


step2、介绍MultiWaveView.java这个类的方法,这个类除了锁屏用外,来电界面也用到了这个类,这就是谷歌的代码的高效的利用率,能写一个类,让2个,或多个界面利用。不得不再次佩服下谷歌的设计这个类的人。

  这个类的方法基本看名字就能看明白,先不写了,等有人留言了,再写出来,基本上ste1的属性配置好了,就能定制自己的锁屏界面了,想要更炫的效果,就只能修改MultiWaveView.java这个类了,像小米的锁屏界面就是修改了这个类,把自己的锁屏界面弄了个音乐播放器的view,可以和锁屏界面切换,其实小米就是修改了这个MultiWaveView.java就能达到想要的效果了。

上一张修改后的图片:

                                                                      android系统锁屏详解【android锁屏解析二】


step 3 :我看到文章被推荐了,就再写点东西,分析以下MultiWaveView.java这个类,其实看java代码先看类的写法,看类继承了哪些类,实现了哪些接口,这样心理就有个大概了,大概就知道代码会走哪些方法了。

public class MultiWaveView extends View {

其实这个类就是一个view类;


再来看看这个类中有没有内部类,或者内部接口什么的?

大致浏览以下发现这个类中有内部接口:

public interface OnTriggerListener {        int NO_HANDLE = 0;        int CENTER_HANDLE = 1;        public void onGrabbed(View v, int handle);        public void onReleased(View v, int handle);        public void onTrigger(View v, int target);        public void onGrabbedStateChange(View v, int handle);    }

通过单词的翻译大概就了解这些方法的作用了,

onGrabbed():抓起handler的触发方法;   onReleased():释放handler的触发方法;

onTrigger():触发方法,就是最后滑动到哪个app了,就会回调这个方法;

onGrabbedStateChange():这个就是触发状态改变的时候回调这个方法;

接口的方法都是回调方法,回调给实现这个接口的类的实现方法;


其实看到这里还有个重要的没有说到:就是状态,有如下几种状态;比如:空闲的状态,刚开始触发,move追踪,抢占触发,结束,对应的静态的final类型的常量如下:

private static final int STATE_IDLE = 0;    private static final int STATE_FIRST_TOUCH = 1;    private static final int STATE_TRACKING = 2;    private static final int STATE_SNAP = 3;    private static final int STATE_FINISH = 4;
这几个状态搞明白了,就来看看触摸事件怎么处理的?


Step 4 :view的触摸事件可以通过onTouchEvent()来监听,来看看庐山真面目:

@Override    public boolean onTouchEvent(MotionEvent event) {        final int action = event.getAction();        boolean handled = false;        switch (action) {            case MotionEvent.ACTION_DOWN:                Xlog.i(TAG,"ACTION_DOWN");                 handleDown(event);                handled = true;                break;            case MotionEvent.ACTION_MOVE:                handleMove(event);                handled = true;                break;            case MotionEvent.ACTION_UP:                Xlog.i(TAG,"ACTION_UP");                mActionCancel = false;                handleMove(event);                handleUp(event);                handled = true;                break;            case MotionEvent.ACTION_CANCEL:                Xlog.i(TAG,"ACTION_CANCEL");                mActionCancel = true;                handleMove(event);                handleUp(event);                handled = true;                break;        }        invalidate();        return handled ? true : super.onTouchEvent(event);    }
从谷歌的方法命名上就能大概知道这个方法有什么作用,谷歌的命名很规范,我们要学习这种命名,简单、明了;

相应的方法会调用一个方法switchToState(),这个是改变状态做相应处理方法,然后根据传入什么的状态常量,做什么处理就可以了。这个细节大家可以看一眼就明白怎么回事了。


step 5:另外补充几个方法:

private void showTargets(boolean animate) { }显示目标target的方法,传入true:表示有动画,false:无动画;

private void hideTargets(boolean animate) { } 隐藏目标target的方法,出入true:表示有动画,false:无动画;

这个显示和隐藏的实现谷歌的实现是:改变Alpha的值来实现的,setAlpha(0.0f)表示隐藏,setAlpha(1.0f) 显示;

private void updateTargetPositions() {  } 这个方法是更新target目标的坐标的方法;


尾声:这些重点方法和流程都说了一下,我相信剩下的细节就没什么了。想做什么修改这个根据客户的需求就可以了。像小米的锁屏,双击出音乐的界面,有播放,上一首,下一首,这个都可以在这个类中做修改;

上传一张图片,看看效果:

                                       android系统锁屏详解【android锁屏解析二】