Android 源码解析之Launcher3之帮助提示的实现方案


先从Launcher.xml看view的结构:


res/launcher.xml下有


        
        
        


        


ScrimView这个类是个FrameLayout的子类,它只实现了Insettable接口,并没有扩展任何元素,可以认为它就是个FrameLayout,暂时不明白它的用意


其它几个include其实都是com.ijinshan.browser.launcher3.Cling类,作者通过这一个类包不同的子view来实现同一种能力且显示效果不同的目的,值得学习.
这里有三个帮助的具体实现:
1.first_run_cling
2.workspace_cling
3.folder_cling


我们可以通过Cling.java这个类为线索去看系统是怎么实现帮助提示的:


1.首先是一些个dismissed:


    static final String FIRST_RUN_CLING_DISMISSED_KEY = "cling_gel.first_run.dismissed";
    static final String WORKSPACE_CLING_DISMISSED_KEY = "cling_gel.workspace.dismissed";
    static final String FOLDER_CLING_DISMISSED_KEY = "cling_gel.folder.dismissed";



它的目的很明显,一旦被关掉的帮助以后不打开了,通过这些个key把它们存在SharedPreferences里头。


public void showFirstRunCling() {
        if (isClingsEnabled() &&
                !mSharedPrefs.getBoolean(Cling.FIRST_RUN_CLING_DISMISSED_KEY, false) &&
                !skipCustomClingIfNoAccounts() ) {
            // If we're not using the default workspace layout, replace workspace cling
            // with a custom workspace cling (usually specified in an overlay)
            // For now, only do this on tablets
            if (!DISABLE_CUSTOM_CLINGS) {
                if (mSharedPrefs.getInt(LauncherProvider.DEFAULT_WORKSPACE_RESOURCE_ID, 0) != 0 &&
                        getResources().getBoolean(R.bool.config_useCustomClings)) {
                    // Use a custom cling
                    View cling = findViewById(R.id.workspace_cling);
                    ViewGroup clingParent = (ViewGroup) cling.getParent();
                    int clingIndex = clingParent.indexOfChild(cling);
                    clingParent.removeViewAt(clingIndex);
                    View customCling = mInflater.inflate(R.layout.custom_workspace_cling, clingParent, false);
                    clingParent.addView(customCling, clingIndex);
                    customCling.setId(R.id.workspace_cling);
                }
            }
            Cling cling = (Cling) findViewById(R.id.first_run_cling);
            if (cling != null) {
//                String sbHintStr = getFirstRunClingSearchBarHint();
                String ccHintStr = getFirstRunCustomContentHint();
//                if (!sbHintStr.isEmpty()) {
//                    TextView sbHint = (TextView) cling.findViewById(R.id.search_bar_hint);
//                    sbHint.setText(sbHintStr);
//                    sbHint.setVisibility(View.VISIBLE);
//                }
                setCustomContentHintVisibility(cling, ccHintStr, true, false);
            }
            initCling(R.id.first_run_cling, 0, false, true);
        } else {
            removeCling(R.id.first_run_cling);
        }
    }






   private void dismissCling(final Cling cling, final Runnable postAnimationCb,
                              final String flag, int duration, boolean restoreNavBarVisibilty) {
        // To catch cases where siblings of top-level views are made invisible, just check whether
        // the cling is directly set to GONE before dismissing it.
        if (cling != null && cling.getVisibility() != View.GONE) {
            final Runnable cleanUpClingCb = new Runnable() {
                public void run() {
                    cling.cleanup();
                    // We should update the shared preferences on a background thread
                    new Thread("dismissClingThread") {
                        public void run() {
                            SharedPreferences.Editor editor = mSharedPrefs.edit();
                            editor.putBoolean(flag, true);
                            editor.commit();
                        }
                    }.start();
                    if (postAnimationCb != null) {
                        postAnimationCb.run();
                    }
                }
            };
            if (duration <= 0) {
                cleanUpClingCb.run();
            } else {
                cling.hide(duration, cleanUpClingCb);
            }
            mHideFromAccessibilityHelper.restoreImportantForAccessibility(mDragLayer);


            if (restoreNavBarVisibilty) {
                cling.setSystemUiVisibility(cling.getSystemUiVisibility() &
                        ~View.SYSTEM_UI_FLAG_LOW_PROFILE);
            }
        }
    }



  上述代码会去判断dismiss过,如果dismiss过,就不会再显示了.


接下来是这些:
 
 private static String FIRST_RUN_PORTRAIT = "first_run_portrait";
    private static String FIRST_RUN_LANDSCAPE = "first_run_landscape";


    private static String WORKSPACE_PORTRAIT = "workspace_portrait";
    private static String WORKSPACE_LANDSCAPE = "workspace_landscape";
    private static String WORKSPACE_LARGE = "workspace_large";
    private static String WORKSPACE_CUSTOM = "workspace_custom";


    private static String FOLDER_PORTRAIT = "folder_portrait";
    private static String FOLDER_LANDSCAPE = "folder_landscape";
    private static String FOLDER_LARGE = "folder_large";



这些东西和:drawIdentifier有关,在attrs里定义它为string,在first_run_cling.xml,workspace_cling.xml,folder_cling.xml里都有定义:launcher:drawIdentifier
不难理解它是用来区分Cling类里,不同的实现的一个标识。Cling就如同一个躯壳,它里面包哪种类型的显示效果,它就显示啥,但这个躯壳它也清楚它自己包的是啥,就是通过这个变量mDrawIdentifier,是字xml


告诉它的,这个躯壳知道自己包的是啥之后,就好做一些细节上的处理.
我个人感觉这个Cling.java写的不够好,它有点违反设计模式里的单一职责。它居然是各种帮助的躯壳,就不应该自己又去知道里面的东西是啥,又根据里头的东西不一样又实现不一样的细节。其中有一段代码我非


常讨厌,就是我接下来要说的:

    private int[] mTouchDownPt = new int[2];


    private Drawable mFocusedHotseatApp;
    private ComponentName mFocusedHotseatAppComponent;
    private Rect mFocusedHotseatAppBounds;


//这个方法显然是FirstRunWorkspaceCling相关的东西
 void setFocusedHotseatApp(int drawableId, int appRank, ComponentName cn, String title,
                              String description) {
....
}



这怎么又有hotSeat相关的代码呢?居然已经是一个躯壳就应该做它里面共有的事情,细节的不一样交给包裹里的东西实现,我是这么认为的.




Cling的初始化之init();

1.first_run_cling:Launcher.onCreate()->Launcher.showFirstRunCling()->Launcher.initCling();
2.workspace_cling:Cling.onClick()->Launcher.dismissFirstRunCling()->showFirstRunWorkspaceCling()->Launcher.initCling()
3.folder_cling:Folder.animateOpen->Launcher.showFirstRunFoldersCling()->Launcher.initCling();



可以看出,都是在要显示的时候初始化


  if (isClingsEnabled() &&
                !mSharedPrefs.getBoolean(Cling.FOLDER_CLING_DISMISSED_KEY, false)) {
            Cling cling = initCling(R.id.folder_cling, R.id.cling_scrim,
                    true, true);
            return cling;
        } else {
            removeCling(R.id.folder_cling);
            return null;
        }




如果发显示不该显示就remove()这个细节很赞!


后面dispatchDraw就是根据它包的不同东西去显示一些不同细节,我想说的是,为啥不能交给它们的子view实现。



































你可能感兴趣的:(Android 源码解析之Launcher3之帮助提示的实现方案)