Android 快速實現APP新手蒙層引導

? ? ? ? 最近在項目開發(fā)中,產品設計出了新功能的用戶引導,非啟動頁面左右滑動類型的引導,而是在APP功能界面上,直接上層彈出蒙層形式展示,其實在過往的開發(fā)中,也有過相同的功能,但是都比較少,就基本上都采用簡單粗暴的直接在XML中布局,然后控制Visible,然后添加點擊事件就行。最近公司APP中,產品提出來的有點多,而且部分引導區(qū)域需要做到事件的穿透,部分不穿透,甚至出現了異形的鏤空,再簡單粗暴的去布局,對于后期XML布局的維護存在一定的成本。于是自己決心花費周末的一個時間,寫一個公共的庫。這個庫一定要簡單,不能再在XML中布局,并且容易理解。先來幾張樣例圖(網圖,和實現功能一樣)

廢話不多說,先下載Demo 看效果,非常小



網圖:


上面是網絡上的圖片,下面是我的實現圖片(圖大,就用三張)

自己在線PS做的圖,有點丑,將就看。

話不多說,源碼:SmartGuideView?到Github去下載吧。

引用方式:

dependencies {

? ? ? ? ? ? implementation fileTree(include: ['*.jar'], dir: 'libs')

? ? ? ? ? ?implementation 'aiven.guide.view:library:1.0.1'

? ? ? ? ? //或者使用api

? ? ? ? ? // api 'aiven.guide.view:library:1.0.1'

}


還是說一下代碼把,這里只是說一下怎么用,API的含義,具體有興趣的朋友可以直接看源碼。

類入口:SmartGuide

創(chuàng)建蒙層。

? ??SmartGuide.newGuide(this)? 這里的this 需要傳入一個Activity或者fragment。需要注意的是,fragment一定要在attach執(zhí)行完畢之后才能去調用,因為歸根接地用的還是activity。

第一個初始化方法:initBaseColor(顏色值)? 初始化引導蒙層的默認背景顏色,一般都是半透明的黑色,所以默認我采用了50%透明度的黑色,可以之定義,如果不知道,就是默認值。

SmartGuide.newGuide(this) .initBaseColor(顏色值)? ?這樣就構建完成了一個沒有引導的蒙層。接下來在蒙層中創(chuàng)建一個用戶引導。這里我將引導命名為層Layer。一個引導(Layer)包含一個蒙層中的鏤空區(qū)域和圖片介紹信息,具體例子就是上面螞蟻花唄那張圖中,白色螞蟻花唄的橫條就是鏤空區(qū)域,下面一行白色文字和手就是圖片介紹信息。

所以我將這兩個分別命名為:Clip 和Panel。

newLayer(Tag) //創(chuàng)建一個引導,并給這個引導指定一個Tag,相當于Id。

所以一個Layer = Clip + Panel 。當然,都不是必須的。這就是接下來的API

buildViewRectClip、buildCustomClip、buildIntroPanel??

不是說兩個嘛?怎么冒出了三個函數?

這里ViewRectClip和CustomeClip 都是Clip,兩種鏤空區(qū)域。

ViewRectClip 是一個根據界面上的一個View 在屏幕上的位置,尺寸計算出鏤空區(qū)域和大小,CustomeClip 是一個絕對位置自定義的裁剪區(qū)域,以根布局左上角為坐標定點,自己設置區(qū)域和偏移,當然這里我增加了Align,這個就不解釋了,程序員做布局基本上都懂。通過buildViewRectClip和buildCustomeClip來設置,參數都是一個Build內部接口,然后返回響應的Clip接口,具體Clip的構建參數見下面的例子中說明。這里不再詳細說,或者直接到github上看。clip 有個API需要特殊說明:asIrregularShape(Bitmap)? 這個是傳入一個異形圖片,以圖片形狀作為鏤空形狀,上圖中有個實例,一個老鼠的造型。

Panel:也通過build方式內部接口回調,Panel也有一個Align,這里的Align和CustomClip的Align 有點區(qū)別,這里的Align是Panel 現對于Clip而言。也就是Pannel 局clip的,上、下、做、右。然后設置offsetX,offsetY設置偏移即可。


點擊事件:OnGuidClickListener? 接口,有三個回調函數,

emptyErrorClicked? ?點擊了非Panel和clip區(qū)域,返回值:true 蒙層直接退出,false不退出

clipClicked? ? 點擊了clip鏤空區(qū)域,這里要說明的是,Clip有個接口是API是setEventPassThrough(boolean),這個是標明是否鏤空區(qū)域點擊事件要穿透到APP自身功能布局中的UI響應。

introClicked? ?點擊了Panel 圖片介紹區(qū)域。

創(chuàng)建完成Layer后可以直接show() 顯示,如果一個蒙層同時要顯示多個Layer,則要先調用over()方法結束上一個layer的參數設置功能,直接newLayer即可,具體見github的多Layer展示方案。


代碼之前,再附帶一下傳送門:SmartView

https://github.com/aiven163/SmartGuideView


代碼實例一:

SmartGuide.newGuide(this)

.initBaseColor(0X80000000)//設置引蒙層背景顏色

? ? ? ? ? ? //新建一個引導

? ? ? ? ? ? .newLayer(TAG_USER_HEADER)

//創(chuàng)建一個鏤空區(qū)域

? ? ? ? ? ? .buildCustomClip(new SmartGuide.ClipPositionBuilder() {

@Override

? ? ? ? ? ? ? ? public CustomClipbuildTarget() {

//構建鏤空區(qū)域圖形,支持CustomClip 和ViewRectClip

? ? ? ? ? ? ? ? ? ? return CustomClip.newClipPos()

.setAlignX(SmartGuide.AlignX.ALIGN_RIGHT)//設置定位水平定位偏向

? ? ? ? ? ? ? ? ? ? ? ? ? ? .setAlignY(SmartGuide.AlignY.ALIGN_TOP)//設置定位垂直定位偏向

? ? ? ? ? ? ? ? ? ? ? ? ? ? .setOffsetX(SmartUtils.dip2px(getApplicationContext(),14))//根據水平定位偏向設置偏移,如果未ALIGN_LEFT,則是距離屏幕左側偏移量,如果是ALIGN_RIGHT 則是距離屏幕右側偏移量

? ? ? ? ? ? ? ? ? ? ? ? ? ? .setOffsetY(SmartUtils.getStatusBarHeight(getApplicationContext())+SmartUtils.dip2px(getApplicationContext(),4))

//設置鏤空裁剪區(qū)域尺寸

? ? ? ? ? ? ? ? ? ? ? ? ? ? .setClipSize(SmartUtils.dip2px(getApplicationContext(),48),SmartUtils.dip2px(getApplicationContext(),48))

.clipRadius(SmartUtils.dip2px(getApplicationContext(),24));

? ? ? ? ? ? ? ? }

})

.buildIntroPanel(new SmartGuide.IntroPanelBuilder() {

@Override

? ? ? ? ? ? ? ? public IntroPanelbuildFacePanel() {

return IntroPanel.newIntroPanel(getApplicationContext())

//設置介紹圖片與clipInfo的對齊信息

? ? ? ? ? ? ? ? ? ? ? ? ? ? .setIntroBmp(R.mipmap.test_face)

.setAlign(SmartGuide.AlignX.ALIGN_LEFT,SmartGuide.AlignY.ALIGN_BOTTOM)

.setSize(SmartUtils.dip2px(getApplicationContext(),151),SmartUtils.dip2px(getApplicationContext(),97))

.setOffset(SmartUtils.dip2px(getApplicationContext(),-20),0);

? ? ? ? ? ? ? ? }

})

.over()//多個newLayer必須用over作為上一個newLayer的結束連接

? ? ? ? ? ? .newLayer(TAG_MUSIC_IMG)

//創(chuàng)建一個鏤空區(qū)域

? ? ? ? ? ? .buildViewRectClip(new SmartGuide.ClipPositionBuilder() {

@Override

? ? ? ? ? ? ? ? public ViewRectClipbuildTarget() {

return ViewRectClip.newClipPos()

.setDstView(R.id.text_pos)

.setPadding(SmartUtils.dip2px(getApplicationContext(),5))

.clipRadius(SmartUtils.dip2px(getApplicationContext(),51));

? ? ? ? ? ? ? ? }

})

.buildIntroPanel(new SmartGuide.IntroPanelBuilder() {

@Override

? ? ? ? ? ? ? ? public IntroPanelbuildFacePanel() {

return IntroPanel.newIntroPanel(getApplicationContext())

//設置介紹圖片與clipInfo的對齊信息

? ? ? ? ? ? ? ? ? ? ? ? ? ? .setIntroBmp(R.mipmap.test_face_music)

.setAlign(SmartGuide.AlignX.ALIGN_LEFT,SmartGuide.AlignY.ALIGN_TOP)

.setSize(SmartUtils.dip2px(getApplicationContext(),120),SmartUtils.dip2px(getApplicationContext(),120))

.setOffset(SmartUtils.dip2px(getApplicationContext(),-100),0);

? ? ? ? ? ? ? ? }

})

.setOnGuidClickListener(new SmartGuide.OnGuidClickListener() {

@Override

? ? ? ? ? ? ? ? public boolean emptyErrorClicked() {

return true;

? ? ? ? ? ? ? ? }

@Override

? ? ? ? ? ? ? ? public void clipClicked(SmartGuide guide, GuidView view, String tag) {

if (TAG_USER_HEADER.equals(tag)) {

Toast.makeText(getApplicationContext(), "點擊了左上角頭像裁剪區(qū)域", Toast.LENGTH_SHORT).show();

? ? ? ? ? ? ? ? ? ? }else if(TAG_MUSIC_IMG.equals(tag)){

Toast.makeText(getApplicationContext(), "點擊了紫色音樂圖標裁剪區(qū)域", Toast.LENGTH_SHORT).show();

? ? ? ? ? ? ? ? ? ? }

}

@Override

? ? ? ? ? ? ? ? public void introClicked(SmartGuide guide, GuidView view, String tag) {

if (TAG_USER_HEADER.equals(tag)) {

Toast.makeText(getApplicationContext(), "點擊了左上角頭像圖片介紹區(qū)域", Toast.LENGTH_SHORT).show();

? ? ? ? ? ? ? ? ? ? }else if(TAG_MUSIC_IMG.equals(tag)){

Toast.makeText(getApplicationContext(), "點擊了紫色音樂圖片介紹區(qū)域", Toast.LENGTH_SHORT).show();

? ? ? ? ? ? ? ? ? ? }

}

})

.show();

}




代碼實例二:

/**

* 根據View 自身位置定位

* @param view

*/

public void showViewPosLayer(View view){

//構建引導

? ? SmartGuide.newGuide(this)

.initBaseColor(0X80000000)//設置引蒙層背景顏色

? ? ? ? ? ? //新建一個引導

? ? ? ? ? ? .newLayer(TAG_MUSIC_IMG)

//創(chuàng)建一個鏤空區(qū)域

? ? ? ? ? ? .buildViewRectClip(new SmartGuide.ClipPositionBuilder() {

@Override

? ? ? ? ? ? ? ? public ViewRectClipbuildTarget() {

return ViewRectClip.newClipPos()

.setDstView(R.id.text_pos)

.setPadding(SmartUtils.dip2px(getApplicationContext(),5))

.clipRadius(SmartUtils.dip2px(getApplicationContext(),51));

? ? ? ? ? ? ? ? }

})

.buildIntroPanel(new SmartGuide.IntroPanelBuilder() {

@Override

? ? ? ? ? ? ? ? public IntroPanelbuildFacePanel() {

return IntroPanel.newIntroPanel(getApplicationContext())

//設置介紹圖片與clipInfo的對齊信息

? ? ? ? ? ? ? ? ? ? ? ? ? ? .setIntroBmp(R.mipmap.test_face_music)

.setAlign(SmartGuide.AlignX.ALIGN_LEFT,SmartGuide.AlignY.ALIGN_TOP)

.setSize(SmartUtils.dip2px(getApplicationContext(),120),SmartUtils.dip2px(getApplicationContext(),120))

.setOffset(SmartUtils.dip2px(getApplicationContext(),-100),0);

? ? ? ? ? ? ? ? }

})

.setOnGuidClickListener(new SmartGuide.OnGuidClickListener() {

@Override

? ? ? ? ? ? ? ? public boolean emptyErrorClicked() {

return true;

? ? ? ? ? ? ? ? }

@Override

? ? ? ? ? ? ? ? public void clipClicked(SmartGuide guide, GuidView view, String tag) {

Toast.makeText(getApplicationContext(), "點擊了紫色音樂圖標裁剪區(qū)域", Toast.LENGTH_SHORT).show();

? ? ? ? ? ? ? ? }

@Override

? ? ? ? ? ? ? ? public void introClicked(SmartGuide guide, GuidView view, String tag) {

Toast.makeText(getApplicationContext(), "點擊了紫色音樂圖標介紹圖片區(qū)域", Toast.LENGTH_SHORT).show();

? ? ? ? ? ? ? ? }

})

.show();

}





最后多個Layer代碼實例:

/**

* 單屏顯示多個layer

* @param view

*/

public void showMultLayer(View view){

SmartGuide.newGuide(this)

.initBaseColor(0X80000000)//設置引蒙層背景顏色

? ? ? ? ? ? //新建一個引導

? ? ? ? ? ? .newLayer(TAG_USER_HEADER)

//創(chuàng)建一個鏤空區(qū)域

? ? ? ? ? ? .buildCustomClip(new SmartGuide.ClipPositionBuilder() {

@Override

? ? ? ? ? ? ? ? public CustomClipbuildTarget() {

//構建鏤空區(qū)域圖形,支持CustomClip 和ViewRectClip

? ? ? ? ? ? ? ? ? ? return CustomClip.newClipPos()

.setAlignX(SmartGuide.AlignX.ALIGN_RIGHT)//設置定位水平定位偏向

? ? ? ? ? ? ? ? ? ? ? ? ? ? .setAlignY(SmartGuide.AlignY.ALIGN_TOP)//設置定位垂直定位偏向

? ? ? ? ? ? ? ? ? ? ? ? ? ? .setOffsetX(SmartUtils.dip2px(getApplicationContext(),14))//根據水平定位偏向設置偏移,如果未ALIGN_LEFT,則是距離屏幕左側偏移量,如果是ALIGN_RIGHT 則是距離屏幕右側偏移量

? ? ? ? ? ? ? ? ? ? ? ? ? ? .setOffsetY(SmartUtils.getStatusBarHeight(getApplicationContext())+SmartUtils.dip2px(getApplicationContext(),4))

//設置鏤空裁剪區(qū)域尺寸

? ? ? ? ? ? ? ? ? ? ? ? ? ? .setClipSize(SmartUtils.dip2px(getApplicationContext(),48),SmartUtils.dip2px(getApplicationContext(),48))

.clipRadius(SmartUtils.dip2px(getApplicationContext(),24));

? ? ? ? ? ? ? ? }

})

.buildIntroPanel(new SmartGuide.IntroPanelBuilder() {

@Override

? ? ? ? ? ? ? ? public IntroPanelbuildFacePanel() {

return IntroPanel.newIntroPanel(getApplicationContext())

//設置介紹圖片與clipInfo的對齊信息

? ? ? ? ? ? ? ? ? ? ? ? ? ? .setIntroBmp(R.mipmap.test_face)

.setAlign(SmartGuide.AlignX.ALIGN_LEFT,SmartGuide.AlignY.ALIGN_BOTTOM)

.setSize(SmartUtils.dip2px(getApplicationContext(),151),SmartUtils.dip2px(getApplicationContext(),97))

.setOffset(SmartUtils.dip2px(getApplicationContext(),-20),0);

? ? ? ? ? ? ? ? }

})

.over()//多個newLayer必須用over作為上一個newLayer的結束連接

? ? ? ? ? ? .newLayer(TAG_MUSIC_IMG)

//創(chuàng)建一個鏤空區(qū)域

? ? ? ? ? ? .buildViewRectClip(new SmartGuide.ClipPositionBuilder() {

@Override

? ? ? ? ? ? ? ? public ViewRectClipbuildTarget() {

return ViewRectClip.newClipPos()

.setDstView(R.id.text_pos)

.setPadding(SmartUtils.dip2px(getApplicationContext(),5))

.clipRadius(SmartUtils.dip2px(getApplicationContext(),51));

? ? ? ? ? ? ? ? }

})

.buildIntroPanel(new SmartGuide.IntroPanelBuilder() {

@Override

? ? ? ? ? ? ? ? public IntroPanelbuildFacePanel() {

return IntroPanel.newIntroPanel(getApplicationContext())

//設置介紹圖片與clipInfo的對齊信息

? ? ? ? ? ? ? ? ? ? ? ? ? ? .setIntroBmp(R.mipmap.test_face_music)

.setAlign(SmartGuide.AlignX.ALIGN_LEFT,SmartGuide.AlignY.ALIGN_TOP)

.setSize(SmartUtils.dip2px(getApplicationContext(),120),SmartUtils.dip2px(getApplicationContext(),120))

.setOffset(SmartUtils.dip2px(getApplicationContext(),-100),0);

? ? ? ? ? ? ? ? }

})

.setOnGuidClickListener(new SmartGuide.OnGuidClickListener() {

@Override

? ? ? ? ? ? ? ? public boolean emptyErrorClicked() {

return true;

? ? ? ? ? ? ? ? }

@Override

? ? ? ? ? ? ? ? public void clipClicked(SmartGuide guide, GuidView view, String tag) {

if (TAG_USER_HEADER.equals(tag)) {

Toast.makeText(getApplicationContext(), "點擊了左上角頭像裁剪區(qū)域", Toast.LENGTH_SHORT).show();

? ? ? ? ? ? ? ? ? ? }else if(TAG_MUSIC_IMG.equals(tag)){

Toast.makeText(getApplicationContext(), "點擊了紫色音樂圖標裁剪區(qū)域", Toast.LENGTH_SHORT).show();

? ? ? ? ? ? ? ? ? ? }

}

@Override

? ? ? ? ? ? ? ? public void introClicked(SmartGuide guide, GuidView view, String tag) {

if (TAG_USER_HEADER.equals(tag)) {

Toast.makeText(getApplicationContext(), "點擊了左上角頭像圖片介紹區(qū)域", Toast.LENGTH_SHORT).show();

? ? ? ? ? ? ? ? ? ? }else if(TAG_MUSIC_IMG.equals(tag)){

Toast.makeText(getApplicationContext(), "點擊了紫色音樂圖片介紹區(qū)域", Toast.LENGTH_SHORT).show();

? ? ? ? ? ? ? ? ? ? }

}

})

.show();

}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容