您的位置:首页 > 移动开发 > Android开发

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

2014-10-23 12:45 399 查看
先从Launcher.xml看view的结构:

res/launcher.xml下有

<!-- The Workspace cling must appear under the AppsCustomizePagedView below to ensure
that it is still visible during the transition to AllApps and doesn't overlay on
top of that view. -->
<com.ijinshan.browser.launcher3.ScrimView
android:id="@+id/cling_scrim"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<include layout="@layout/first_run_cling"
android:id="@+id/first_run_cling"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<include layout="@layout/workspace_cling"
android:id="@+id/workspace_cling"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />

<include layout="@layout/folder_cling"
android:id="@+id/folder_cling"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />


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实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐