最近每次版本更新都會(huì)在UI變動(dòng)或加了新功能的地方加一個(gè)引導(dǎo)蒙層頁面(新功能標(biāo)記、文案和一個(gè)“知道了”的按鈕)贰谣,有時(shí)候一個(gè)版本會(huì)加三四個(gè)頁面硬霍,原來的做法是:
- 1.在每個(gè)Activity的布局文件外層添加一個(gè)FrameLayout(這方法好蠢,又要嵌套一層布局)瘦真;
- 2.再將需要顯示的引導(dǎo)頁布局加在后面(或用include的方式);
- 3.寫兩個(gè)方法往史,獲取和設(shè)置是否顯示了該引導(dǎo)頁的判斷仗颈,存儲(chǔ)到SharedPreferences;
- 4.最后在對(duì)應(yīng)Activity頁面添加對(duì)應(yīng)控制引導(dǎo)頁顯隱的邏輯
每添加一個(gè)頁面就要重復(fù)上面四個(gè)步驟,而且之后版本迭代需要去掉這些冗余代碼時(shí)也比較麻煩椎例,改動(dòng)的地方比較多挨决,不利于管理。
這方法太笨了订歪,不能純粹只為了完成功能呀脖祈,于是想了一個(gè)簡(jiǎn)單有效的方法。
首先解決避免改動(dòng)原Activity布局的問題刷晋,只要通過findViewById(android.R.id.content)獲取Activity根布局下的FrameLayout, 再將需要添加的引導(dǎo)頁布局addView(view)進(jìn)入就可以了
FrameLayout rootLayout = (FrameLayout) activity.findViewById(android.R.id.content);
View layoutView = View.inflate(activity, layoutId, null);
rootLayout.add(layoutView);
這樣就解決了改動(dòng)Activity布局的問題盖高,同時(shí)也將引導(dǎo)頁的內(nèi)容單獨(dú)放在一個(gè)Layout文件(說得好像是廢話,這不是必須的嗎眼虱,不過我還真看過有人將所有布局代碼都放在Activity的布局文件的 o(╯□╰)o)
然后后面的優(yōu)化就好辦了喻奥。將存儲(chǔ)到SharedPreferences引導(dǎo)頁是否已展示的方法增加一個(gè)pageTag的參數(shù),通過外部使用時(shí)傳入捏悬,這樣就避免了每個(gè)頁面都寫同類型的方法的問題了撞蚕。
最后將上面所說的方法封裝在一個(gè)類GuidePage,使用時(shí)傳入activity, layoutId, knowViewId(知道了按鈕)和pageTag即可邮破,寫好這個(gè)工具類后诈豌,之后再需要增加引導(dǎo)頁時(shí)只需要:
1.寫一個(gè)引導(dǎo)頁面的布局仆救;
2.在對(duì)應(yīng)的Activity頁面調(diào)用這個(gè)工具方法即可抒和;
private void apply(@LayoutRes int layoutId, @IdRes int knowViewId, String pageTag) {
FrameLayout rootLayout = (FrameLayout) activity.findViewById(android.R.id.content);
View layoutView = View.inflate(activity, layoutId, null);
rootLayout.addView(layoutView);
layoutView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
layoutView.findViewById(knowViewId).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
rootLayout.removeView(layoutView);
SpUtil.setHasShowedGuidePage(activity, pageTag, true);
}
});
}
//調(diào)用時(shí)矫渔,直接在Activity寫
if(!SpUtil.hasShowedGuidePage()){
new GuidePage(this).apply(R.layout.view_home_guide_page, R.id.home_guide_page_know, pageTag);
}
減少了大量重復(fù)代碼,不用修改原來的布局文件摧莽,后期刪除也比較方便庙洼,簡(jiǎn)單吧 -_-
理論上,這樣就完了镊辕,不過程序員比較喜歡折騰油够,這樣直接在構(gòu)造器寫四個(gè)參數(shù)好像不太好看吧,好像可以用建造者模式改下征懈,于是就開始了將簡(jiǎn)單的事情搞復(fù)雜的道路-_-
------------------------------分割線------------------------------------
期待這樣調(diào)用就可以了
new GuidePage.Builder(this)
.setLayoutId(R.layout.view_home_guide_page)
.setKnowViewId(R.id.home_guide_page_know)
.setPageTag(pageTag)
.builder()
.apply();
建造者模式有兩種寫法石咬,一種是有設(shè)計(jì)者的(有序),一種是無設(shè)計(jì)者的(無序)卖哎,AlertDialog是無設(shè)計(jì)者的方式鬼悠,簡(jiǎn)單一點(diǎn),比較喜歡這種連寫的方式亏娜。不記得建造者模式的可以看篇文章回憶下:[Android] 設(shè)計(jì)模式-建造者模式
建一個(gè)GuidePage的類焕窝,里面有個(gè)Builder的內(nèi)部類,通過內(nèi)部類設(shè)置activity, layoutId, knowViewId等參數(shù)维贺。存儲(chǔ)引導(dǎo)頁是否已展示的方法好像可以直接寫在GuidePage它掂,就不用在外部判斷了,不過這樣要執(zhí)行一些無用的代碼溯泣,不適合虐秋;還有pageTag好像可以直接用activity.getClass().getSimpleName(), 也不用傳這個(gè)值了,不過如果同一個(gè)Activity有兩個(gè)引導(dǎo)頁(如不同F(xiàn)ragment需要不同引導(dǎo)頁)就不適用了垃沦,還是只能通過參數(shù)傳入好點(diǎn)
好吧客给,這么簡(jiǎn)單,就不多說了栏尚,直接上代碼:
public class GuidePage {
private int layoutId;
private int knowViewId;
private String pageTag;
private boolean mCancel = false;
private Activity activity;
private FrameLayout rootLayout;
private View layoutView;
//設(shè)置為 protected或private, 不被外部直接調(diào)用
protected GuidePage(){
}
public static class Builder{
private GuidePage guidePage = new GuidePage();
public Builder(Activity activity){
guidePage.activity = activity;
}
public Builder setLayoutId(@LayoutRes int layoutId){
guidePage.layoutId = layoutId;
return this;
}
public Builder setKnowViewId(@IdRes int knowViewId){
guidePage.knowViewId = knowViewId;
return this;
}
/**
* 引導(dǎo)唯一的標(biāo)記起愈,用作存儲(chǔ)到SharedPreferences的key值,不同引導(dǎo)頁必須不一樣
* @param pageTag
* @return
*/
public Builder setPageTag(String pageTag){
guidePage.pageTag = pageTag;
return this;
}
public Builder setCloseOnTouchOutside(boolean cancel){
guidePage.mCancel = cancel;
return this;
}
public GuidePage builder(){
if(TextUtils.isEmpty(guidePage.pageTag)){
throw new RuntimeException("the guide page must set page tag");
}
guidePage.setLayoutView();
guidePage.setKnowEvent();
guidePage.setCloseOnTouchOutside();
return guidePage;
}
}
public void setLayoutView(){
rootLayout = (FrameLayout) activity.findViewById(android.R.id.content);
layoutView = View.inflate(activity, layoutId, null);
}
public void setKnowEvent(){
if(layoutView!=null) {
layoutView.findViewById(knowViewId).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
cancel();
}
});
}
}
public void setCloseOnTouchOutside(){
if(layoutView == null)
return;
layoutView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(mCancel){
cancel();
}
return true; //消費(fèi)事件译仗,不下發(fā)
}
});
}
public void apply(){
rootLayout.addView(layoutView);
}
public void cancel(){
if(rootLayout!=null && layoutView!=null) {
rootLayout.removeView(layoutView);
GuidePageManager.setHasShowedGuidePage(activity, pageTag, true);
}
}
}
下面是判斷頁面是否顯示引導(dǎo)頁的類抬虽,或者用來定義一些靜態(tài)的pageTag也行
public class GuidePageManager {
private GuidePageManager(){
}
/**
* @param activity
* @param pageKey 使用時(shí),傳入的值必須和GuidePage設(shè)置的值一樣
* @return
*/
public static boolean hasNotShowed(Activity activity, String pageKey){
return !hasShowedGuidePage(activity, pageKey);
}
public static void setHasShowedGuidePage(Context context, String key, boolean hasShowed){
SharedPreferences settings= context.getSharedPreferences(context.getPackageName(), 0);
SharedPreferences.Editor editor=settings.edit();
editor.putBoolean(key, hasShowed);
editor.commit();
}
private static boolean hasShowedGuidePage(Context context, String key){
SharedPreferences settings=context.getSharedPreferences(context.getPackageName(), 0);
boolean value=settings.getBoolean(key, false);
return value;
}
}
最后纵菌,使用方法
if(GuidePageManager.hasNotShowed(this, MainActivity.class.getSimpleName())){
new GuidePage.Builder(this)
.setLayoutId(R.layout.view_home_guide_page)
.setKnowViewId(R.id.btn_home_act_enter_know)
.setPageTag(MainActivity.class.getSimpleName())
.builder()
.apply();
}
完了阐污。
Github代碼: GuidePageManage
首發(fā)于: Android用建造者模式實(shí)現(xiàn)一個(gè)新功能引導(dǎo)頁
---EOF---