第一部分:Launcher APP 组成分析(二)

来源:互联网 发布:黄金白银套利软件 编辑:程序博客网 时间:2024/06/05 07:13

上一章节介绍到Launcher的四大组件组成、Launcher layout xml的组成及使用到的数据库表 favorites | screens


本章简介:

  1. DragLayer组成分析

  2. Workspace及ScreenView组成分析

  3. CellLayout及CellScreen组成分析

  4. Shortcut组成分析

  5. Hotseats组成分析

  6. DeleteZone组成分析



第一部分:Launcher APP组成分析(二)


从Launcher.xml 中看到Launcher的布局由最外层的DragLayer包裹着,中间由Workspace、Hotseats及DeleteZone几个主要组成部件构成。先抛开桌面上的数据如何读取,如果读者希望在自己写代码的过程中有一个直观的显示感受,可以不妨放写图片或者文字来临时填放用于调试运行。


图(1)


1.DragLayer 组成分析:

    从组成来讲,DragLayer最重要的部分是用于显示壁纸背景,关于拖动的部分,等到分析到触摸再拿来分析。

    壁纸,MIUI系统中将壁纸显示的方式使用SharedPreferences的方式存储。


        /** *功能: 桌面背景显示, 从配置表中读取壁纸的显示方式 *调用: 使用于Launcher.java */public void updateWallpaper() {String wallpaperScrollType = PreferenceManager.getDefaultSharedPreferences(mContext).getString("pref_key_wallpaper_scroll_type", "byTheme");        if (wallpaperScrollType.equals("byTheme")){        wallpaperScrollType = getResources().getString(R.string.wallpaper_scrolling);        }        mWpScrolling = false;        if (wallpaperScrollType.equals("left")) {        mWpOffsetX = 0F;        } else if (wallpaperScrollType.equals("center")) {        mWpOffsetX = 0.5F;        } else if (wallpaperScrollType.equals("right")) {        mWpOffsetX = 1F;        } else {        mWpScrolling = true;                    }            mLauncher.getWindow().setFormat(PixelFormat.TRANSPARENT);mWallpaper = null;updateWallpaperOffset();}/** *功能: 壁纸显示起点 */public void updateWallpaperOffset() {if (mWallpaper == null) {mWallpaperManager.setWallpaperOffsetSteps(mWpStepX, mWpStepY);if (getWindowToken() == null) {removeCallbacks(OffsetUpdater);postDelayed(OffsetUpdater, 50L);}else {try {WindowManagerGlobal.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(getWindowToken(), mWpOffsetX, mWpOffsetY, mWpStepX, mWpStepY);} catch (RemoteException e) { }}}else {int offsetX = (int)((float)(mWpWidth - mScreenSize.x) * mWpOffsetX);if (mOldOffsetX != offsetX) {mOffsetChanged = true;}mOldOffsetX = offsetX;}}public void updateWallpaperOffset(float xStep, float yStep, float xOffset, float yOffset) {if (mWpScrolling && mWpOffsetX != xOffset) {mWpStepX = xStep;mWpStepY = yStep;mWpOffsetX = xOffset;mWpOffsetY = yOffset;updateWallpaperOffset();}}public void updateWallpaperOffsetAnimate(final float xStep, final float yStep, final float xOffset, final float yOffset) {final float xStepDelta = xStep - mWpStepX;final float yStepDelta = yStep - mWpStepY;final float mWpOffsetXDelta = xOffset - mWpOffsetX;                final float mWpOffsetYDelta = yOffset - mWpOffsetY;                        ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.0f, 0.0f);                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float f = ((Float)animation.getAnimatedValue()).floatValue();updateWallpaperOffset(xStep - f * xStepDelta, yStep - f * yStepDelta, xOffset - f * mWpOffsetXDelta, yOffset - f * mWpOffsetYDelta);}});                        valueAnimator.start();}



可以看到,Wallpaper在DragLayer中分三种类型“left”, "right", "center" 来显示,根据壁纸的大小来计算X,Y的偏移量,updateWallpaperOffsetAnimate主要是用于拖动时动画显示滑动到指定位置。


2.Workspace及ScreenView组成分析

    从代码中可以看到Workspace继承与DragableScreenView,DragableScreenView再继承与ScreenView,由于DragableScreenView主要是用于处理触摸动作,这里暂时不做分析,直接看ScreenView。ScreenView是一个ViewGroup,Workspace如果构成的ViewGroup呢?这里必须要涉及到CellLayout及CellScreen,因为这两个组件才是组成Workspace的Viewgroup的元素。实例图如下:


图(二)

CellScreen.xml的layout:

<cn.minking.launcher.CellScreen android:animationCache="false"     android:layout_width="fill_parent" android:layout_height="fill_parent"    xmlns:android="http://schemas.android.com/apk/res/android">    <FrameLayout android:id="@id/background_container"         android:visibility="invisible"         android:animationCache="false"         android:layout_width="fill_parent"         android:layout_height="fill_parent">                ......        ......            </FrameLayout>    <cn.minking.launcher.CellLayout android:id="@id/cell_layout"         android:paddingBottom="@dimen/workspace_cell_padding_bottom"         android:animationCache="false"         android:layout_width="fill_parent"         android:layout_height="fill_parent" /></cn.minking.launcher.CellScreen>


在Launcher的Model将数据读取给CellScreen,然后将每个CellScreen使用addView的方式添加至ViewGroup, 使用 onLayout显示出来,至于详细的步骤会在后续详细的分析。


3. CellScreen | CellLayout组成分析

    CellLayout被分割成Horizontal*Vetical个单元格,下图中示为4x4的CellLayout,此处可以根据屏幕的分辨率不同设置不同的大小,比如MIUI现在使用的则是4x5的布局;


图(三)

    // 横向及纵向的单元格个数    mHCells = ResConfig.getCellCountX();    mVCells = ResConfig.getCellCountY();


    每个单元格的大小及边界距离:

        Resources resources = context.getResources();        mCellWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width);        mCellHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height);        mWidgetCellPaddingTop = resources.getDimensionPixelSize(R.dimen.workspace_widget_padding_top);        mWidgetCellPaddingBottom = resources.getDimensionPixelSize(R.dimen.workspace_widget_padding_bottom);        mPaddingTop = resources.getDimensionPixelSize(R.dimen.workspace_padding_top);        mPaddingLeft = resources.getDimensionPixelSize(R.dimen.workspace_padding_side);        mPaddingRight = mPaddingLeft;


    一个View控件可以占有单个单元格,比如APP图标或者Shortcut快捷方式,也可以一个View控件占有多个单元格,比如2x2的时钟,或者4x4的时钟。

        // 标识单元格视图的二维数组        int ai[] = new int[]{mHCells, mVCells};        int aiBak[] = new int[]{mHCells, mVCells};        mOccupiedCell = (View[][])Array.newInstance(View.class, ai);        mOccupiedCellBak = (View[][])Array.newInstance(View.class, aiBak);


    此部分和原生的Android的launcher是类似的,原生的launcher使用的pagedview,同样是继承与ViewGroup,同样也使用了CellLayout,区别是MIUI多了CellScreen,为何这么做?由于MIUI是单界面操作,所以在桌面需要更多的操作,比如进入Widget编辑模式。


4. ShortCut组成分析:

    这部分本应该是需要和Widget一起分析,但是MIUI中增加了Gadget,涉及到主题资源的引入,所以在此我们先不分析Widget。

    Launcher.java中创建Shortcut布局的接口,看到调用的是application layout

    Launcher.java    /**     * 功能: 以Layout application为样式创建快捷方式的布局     * @param viewgroup     * @param shortcutinfo     * @return     */    private ShortcutIcon createShortcutIcon(ViewGroup viewgroup, ShortcutInfo shortcutinfo){        return ShortcutIcon.fromXml(R.layout.application, this, viewgroup, shortcutinfo);    }        ShortcutIcon.java    /** * 功能: 从XML中的得到快捷图标的布局  * @param layout * @param launcher * @param viewgroup * @param shortcutinfo * @return */static ShortcutIcon fromXml(int layout, Launcher launcher, ViewGroup viewgroup, ShortcutInfo shortcutinfo){ShortcutIcon shortcutIcon = (ShortcutIcon)LayoutInflater.from(launcher).inflate(layout, viewgroup, false);shortcutIcon.updateInfo(launcher, shortcutinfo);    return shortcutIcon;}


application.xml

<cn.minking.launcher.ShortcutIcon     android:background="@drawable/shortcut_selector"     android:focusable="true"     android:animationCache="false"     android:layout_width="fill_parent"     android:layout_height="fill_parent"  xmlns:android="http://schemas.android.com/apk/res/android">        <!-- 图标阴影 -->      <include layout="@layout/icon_shadow" />        <!-- 创建文件夹时显示的背景 -->    <ImageView         android:layout_gravity="top|center"         android:id="@id/icon_folder_creation_bg"         android:visibility="invisible"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_marginLeft="@dimen/icon_side_margin"         android:layout_marginRight="@dimen/icon_side_margin"         android:src="@drawable/icon_folder"         android:scaleType="centerInside" />        <!-- 图标 -->        <include layout="@layout/icon_icon" />    <!-- 标题 -->    <include layout="@layout/icon_title" />    <!-- 消息个数 -->    <include layout="@layout/icon_message" /></cn.minking.launcher.ShortcutIcon>


5. Hotseats组成分析

    Hotseats采用的是线性布局LinearLayout, 根据MAX SEAT的个数,依次布局


图(四)

    Hotseats.java    @Override    protected void onFinishInflate() {super.onFinishInflate();for (int i = 0; i < MAX_SEATS; i++) {LayoutInflater.from(mContext).inflate(R.layout.hotseat_button, this, true);}    }
    HotseatButton.java    public void bind(ItemIcon itemicon, DragController dragcontroller){    mIcon = itemicon;        // 构建一个FrameLayout, 将HOT Seat中的各个ItemIcon加人到Layout中    addView(itemicon);    if (itemicon instanceof DropTarget) {    dragcontroller.addDropTarget((DropTarget)itemicon);}    }


6. DeleteZone组成分析

    DeleteZone默认是隐藏的,等有Item被拖动时才会出现在屏幕的顶部。布局很简单,就以launcher.xml中布局显示。此布局绑定了几个动画及拖动的操作,等后续分析拖动时再详细讲解。


@Override    protected void onFinishInflate() {        super.onFinishInflate();        // 垃圾箱图标        mTrashIcon = (ImageView)findViewById(R.id.trash);        // 提示信息        mEditingTips = (TextView)findViewById(R.id.editing_tips);        mEditingTips.setDrawingCacheEnabled(true);                // 显示及消失的动画, 淡入淡出及伸缩的效果        mFadeIn = AnimationUtils.loadAnimation(getContext(), R.anim.fade_in);        mFadeOut = AnimationUtils.loadAnimation(getContext(), R.anim.fade_out);        mShrinkToTop = AnimationUtils.loadAnimation(getContext(), R.anim.shrink_to_top);        mShrinkToTop.setAnimationListener(this);        mStretchFromTop = AnimationUtils.loadAnimation(getContext(), R.anim.stretch_from_top);        mTransition = (TransitionDrawable)mTrashIcon.getBackground();    }



0 0
原创粉丝点击