1. 程式人生 > >Android開發之高亮引導

Android開發之高亮引導

看下圖,今天的任務就是它了,app 的高亮引導的實現,找到幾個github上面已經實現的庫,下載下來原始碼對比分析實現原理,整理自己的知識體系。下面是其中一個的效果圖(我用DialogFragment實現了引導但是並沒有做高亮實現,補充說明一點:該篇部落格最好配合原始碼對比檢視,不然感覺有那麼點抽象,不知所云)

下面是找到的四個庫的連結地址

ShowcaseView

通過android studio匯出shape包下uml不難發現,這些定製shape就是為高亮顯示用的shape,updateTarget方法定義用於更新檢視。

 /**
  * Update shape bounds if necessary
  */
void updateTarget(Target target);

NoShape僅僅是實現了Shape,見名知其意,使用NoShape則不需要高亮顯示,RectangleShape則矩形高亮,CircleShape圓形高亮,RectangleShape內部定義adjustToTarget變數用於判斷是否調整範圍,至於這裡的onDraw沒什麼好說的,略過

 @Override
    public void updateTarget(Target target) {
        if (adjustToTarget) {
            Rect bounds = target.getBounds();
            height = bounds.height();
            if
(fullWidth) width = Integer.MAX_VALUE; else width = bounds.width(); init(); } }

CircleShape相比較於RectangleShape的區別在於一個是用rect一個是radius,一個drawRect一個drawCircle,updateTaget方法也有所不同

  @Override
  public void updateTarget(Target target) {
      if (adjustToTarget)
         radius = getPreferredRadius(target.getBounds());
  }

  public
static int getPreferredRadius(Rect bounds) { return Math.max(bounds.width(), bounds.height()) / 2; }

updateTarget方法都有用到Taget,這裡的Taget只是一個範圍測量目的new 出一個Rect,而MaterialShowcaseView自定義控制元件使用到的是Taget的實現類ViewTarget,內部實現程式碼比較簡單,就我個人而言可以get到一點

// 獲取在當前視窗內的絕對座標
View.getLocationInWindow()  

// 獲取在整個螢幕內的絕對座標,注意這個值是要從螢幕頂端算起,也就是包括了通知欄的高度。
View.getLocationOnScreen()     

AnimationFactory 和 IAnimationFactory是關於View動畫相關的定製,主要是fadeInView 和fadeOutView效果,供MaterialShowcaseView呼叫,IShowcaseListener和IDetachedListener定義的介面回撥函式,ShowcaseConfig提供了初始化MaterialShowcaseView的基本配置,預設遮蓋層顏色dd335075,預設高亮顯示圖形CircleShape,PrefsManager類只是一個簡單的資料快取輔助類

MaterialShowcaseSequence類提供了addSequenceItem和start 、showNextItem顯示引導View檢視的方法,addSequenceItem方法通過MaterialShowcaseView的Buidler構建例項,並根據上面提到的ShowcaseConfig非空進行初始化MaterialShowcaseView配置

 public MaterialShowcaseSequence addSequenceItem(View targetView, String title, String content, String dismissText) {

        MaterialShowcaseView sequenceItem = new MaterialShowcaseView.Builder(mActivity)
                .setTarget(targetView)
                .setTitleText(title)
                .setDismissText(dismissText)
                .setContentText(content)
                .build();

        if (mConfig != null) {
            sequenceItem.setConfig(mConfig);
        }

        mShowcaseQueue.add(sequenceItem);
        return this;
    }

這個類我們要理解透徹有必要了解這個類的具體用法:Queue< E >,當我第一次看到程式碼內部呼叫下面這些方法簡直了一頭霧水,沒搞懂他具體實現在哪裡,呼叫這些介面定義得方法何用

 mShowcaseQueue.add(sequenceItem);

 mShowcaseQueue.poll();

下來看看介面Queue< E >的具體定義


public interface Queue<E> extends Collection<E> {
    /**
     * 將指定的元素插入到該佇列中,如果由於容量限制,如法插入成功返回false,插入佇列資料不能為空
     */
    boolean add(E e);

    /**
     *如果不違反容量限制的話,將指定的元素插入到該佇列中當使用容量限制該方法通常是最好的add方法新增,
     *能不能插入一個元素如果不能則通過丟擲一個異常。
     *如果新增型別不對,丟擲ClassCastException,防止它被新增到該佇列
     *丟擲NullPointerException異常如果指定元素為null,此佇列不允許空元素
     */
    boolean offer(E e);

    /**
     *檢索並刪除該佇列的頭
     */
    E remove();

    /**
     *檢索並刪除該佇列的頭,如果該佇列為空,則返回Null。
     */
    E poll();

    /**
     *檢索,但不刪除此佇列的頭。
     *丟擲NoSuchElementException,如果佇列為空
     */
    E element();

    /**
     *檢索,但不刪除此佇列的頭,如果該佇列為空,則返回Null
     */
    E peek();
}

LinkedList對Queue做了具體實現,所以在MaterialShowcaseSequence建構函式裡面例項Queue例項的是一個LinkedList,瞬間感覺上面方法的呼叫不再那麼抽象了吧,這種感覺有木有??好吧原諒我吧,是我java基礎不牢!!


 public MaterialShowcaseSequence(Activity activity) {
        mActivity = activity;
        mShowcaseQueue = new LinkedList<>();
    }

public class LinkedList<E> extends AbstractSequentialList<E> implements
        List<E>, Deque<E>, Queue<E>, Cloneable, Serializable {

          //.......略,詳情參考原始碼...........
}

MaterialShowcaseSequence 呼叫start方法 之後poll方法幹掉了佇列裡面當前的view,再次判斷佇列是否還有view有就需要上面提到的showNextItem方法,間接呼叫了介面回撥和show方法,定製動畫也在這裡被呼叫,具體請參考原始碼。

最後再來一觀MaterialShowcaseView,內部定義Builder建構函式初始化MaterialShowcaseView例項,提供基本屬性配置,builder根據已配置屬性選擇shape,Builder模式的運用實在不想再說,就這樣吧,這個自定義控制元件用到的核心有兩點:addOnGlobalLayoutListener和PorterDuff.Mode,檢視層級變化引起onGlobalLayout回撥到setTaget,從而達到調整高亮顯示位置變化,而高亮顯示部分的繪製核心利用畫筆Xfermode,下列是onDraw繪製核心程式碼

 @Override
 protected void onDraw(Canvas canvas) {
      super.onDraw(canvas);

      //........略過圖片資源回收和條件判斷...................

      // clear canvas
      mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

      // draw solid background
      mCanvas.drawColor(mMaskColour);

      // Prepare eraser Paint if needed
      if (mEraser == null) {
          mEraser = new Paint();
          mEraser.setColor(0xFFFFFFFF);
          mEraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
          mEraser.setFlags(Paint.ANTI_ALIAS_FLAG);
      }

      // draw (erase) shape
      mShape.draw(mCanvas, mEraser, mXPosition, mYPosition, mShapePadding);

      // Draw the bitmap on our views  canvas.
      canvas.drawBitmap(mBitmap, 0, 0, null);
  }

還有一些方法塊的定義方便我們管理ShowcaseView的狀態,以便以控制下次是否還彈出高亮引導顯示resetSingleUse和resetAll,不得不感嘆,一個Mode可以玩出這麼多花樣!!!

TourGuide 、ShowTipsView

這個庫的實現原理一模一樣,這個庫的動畫效果更好,還加了一個縮放的高亮指示動畫,但是就程式碼層次而言,僅支援圓形高亮,太單一了,需求變更還得自己修改,程式碼的邏輯層次感覺沒ShowcaseView庫的清晰,效果圖就不貼了,有興趣自己下載執行,我果斷放棄該庫..

ShowTipsView庫相比較於TourGuide要好不少,程式碼層次也清晰了不少,同樣的實現原理同樣的builder模式,保留意見(相比較於ShowcaseView,還是更喜歡前者,人就這樣對“第一次”總是有那麼一種難以言語的情緒)

Hightlight

洪洋的Hightlight庫支援同時高亮顯示多個View,定製顯示佈局,simple效果用的ImageView,效果非常漂亮當然你也可以用其他佈局定製開發,下面是效果圖:

程式碼呼叫例項

 private void showTipMask()
    {
        mHightLight = new HighLight(MainActivity.this)//
                .anchor(findViewById(R.id.id_container))//如果是Activity上增加引導層,不需要設定anchor
        .addHighLight(R.id.id_btn_important_right,R.layout.info_gravity_right_up, new HighLight.OnPosCallback(){


            @Override
            public void getPos(float rightMargin, float bottomMargin, RectF rectF, HighLight.MarginInfo marginInfo) {
                marginInfo.rightMargin = rightMargin;
                marginInfo.topMargin = rectF.top + rectF.height();
            }
        })
        .addHighLight(R.id.id_btn_whoami, R.layout.info_gravity_left_down, new HighLight.OnPosCallback() {


            @Override
            public void getPos(float rightMargin, float bottomMargin, RectF rectF, HighLight.MarginInfo marginInfo) {
                marginInfo.leftMargin = rectF.right - rectF.width()/2;
                marginInfo.bottomMargin = bottomMargin + rectF.height();
            }
        })
        .setClickCallback(new HighLight.OnClickCallback() {
            @Override
            public void onClick() {
                Toast.makeText(MainActivity.this,"clicked",Toast.LENGTH_SHORT).show();
            }
        });

        mHightLight.show();
    }

這個庫的內部實現原理也有點點區別,在layout呼叫buildMask方法得到需要顯示 的bitmap,最後ondraw直接繪製bitmap,程式碼層次上面來說這個做法非常地PL,Xfermode也不同其他幾個庫PorterDuff.Mode.DST_OUT(貌似其他庫都用CLEAR)

 private void buildMask()
    {
        mMaskBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(mMaskBitmap);
        canvas.drawColor(maskColor);
        mPaint.setXfermode(MODE_DST_OUT);
        mHighLight.updateInfo();
        for (HighLight.ViewPosInfo viewPosInfo : mViewRects)
        {
            canvas.drawRoundRect(viewPosInfo.rectF, DEFAULT_RADIUS, DEFAULT_RADIUS, mPaint);
        }
    }

小結

看了幾個庫還是做個小結,如果開發使用一個介面多個高亮引導或者要定製引導檢視建議用Hightlight庫,如果使用純文字相關元素高亮引導,建議用ShowcaseView庫,這塊的知識點涉及到兩點:畫筆設定Xfermode和 ViewTreeObserver.OnGlobalLayoutListener,重新瞭解了Queue與MessageQueue相關的知識。

參考資料

相關推薦

Android開發引導

看下圖,今天的任務就是它了,app 的高亮引導的實現,找到幾個github上面已經實現的庫,下載下來原始碼對比分析實現原理,整理自己的知識體系。下面是其中一個的效果圖(我用DialogFragment實

android開發仿中國建設銀行App

皇天不負有心人,今天終於被我找到了這篇神文!關於高仿中國建設銀行App的一篇Blog,於是我就不自覺的把它消化成了我的東西了,嘿嘿!不過我是有節操滴,在本文的最後我貼上了此文轉載於哪裡?也希望各位在以後的學習道路上,不要做忘恩負義的人! 各位,準備好了嗎?讓我們一起來看看大

Android引導頁的簡單實現

       前段時間公司APP有需求做一個內部的高亮引導頁,我之所以說內部,因為外部也有引導頁(這不是廢話嘛,-_-||)。具體的樣式想必大家都很清楚,就是那種在某個頁面上進行操作指引的那種效果。本文著重說了內部引導頁,是為了區別於外部引導頁,外部引導頁就是那種啟動app時

ArcGIS for Android示例解析要素-----HighlightFeatures

  HighlightFeatures 要素高亮化功能,相信有其他gis開發經營的開發人員都有過相應的實現經驗,對於高亮要素,簡單說起來就是我們查詢的或識別出來的要素進行渲染,讓其突出顯示而已,這個例子中涉及後面要介紹的識別的內容,我們只簡單介紹相關的知識,主要介紹要素物件

Android開發使用ViewPager做引導頁面

引導頁面相信大家都不會陌生,安裝了一個新的App後第一次開啟,都會有類似下圖,相當於說明文件 實現效果 程式目錄結構 在主layout裡main.xml定義一個幀佈局,在viewPager上有多少頁就顯示多少個點 <?xml version="1.0" enc

Android開發Material Design體驗開源專案篇

介於擬物和扁平之間的Material Design自面世以來,便引起了很多人的關注與思考,就此產生的討論也不絕於耳。本文詳細介紹了在Android開發者圈子裡頗受青睞的十個Material Design開源專案,從示例、FAB、選單、動畫、Ripple到Dialog,看被稱為“Google第一次在

Android開發getX,getRawX,getWidth,getTranslationX等的區別

save string hlist getwidth sta 是我 touch 項目 寬度 轉載請註明出處:http://blog.csdn.net/dmk877/article/details/51550031 好久沒寫博客了,最近工作確實挺忙的,剛剛結束了一個

Android 開發Windows環境下Android Studio安裝和使用教程(圖文詳細步驟)

9.png 虛擬機 jdk版本 編寫 clip 開發平臺 集成開發 arc 電腦安裝 鑒於谷歌最新推出的Android Studio備受開發者的推崇,所以也跟著體驗一下。 一、介紹Android Studio Android Studio 是一個Android

Android開發AudioManager(音頻管理器)具體解釋

應該 數量 service eth out 開發 要求 type 路由 AudioManager簡單介紹: AudioManager類提供了訪問音量和振鈴器mode控制。使用Context.getSystemService(Context.AUDIO_SERVICE)

【入門篇】ANDROID開發BUG專講

world 自然 執行 類型 效率 str 積累 全部 href 話說諸葛亮是一個優秀的程序員,每個錦囊都是應對不同的case而編寫的。可是優秀的程序員也敵只是更優秀的bug。六出祈山。七進中原,鞠躬盡瘁,死而後已的諸葛亮僅僅由於有一

Android TV 選中顯示

add 頁面 androi radi ren att set lose main 1、開發Android TV APP, 使用遙控器選中按鈕或者選著其它菜單 如果沒有高亮顯示,就看不出選中哪個按鈕或者菜單 2、在drawable 添加 border_red.xml 設置選中

android開發merge結合include優化布局

ted com match clas you title example ews 文件的 merge結合include優化android布局,效果不知道。個人感覺使用上也有非常大的局限。只是還是了解一下。記錄下來。 布局文件都要有根節點,但androi

Android開發增量更新

avt exp chm 這一 font ams extern city ron 一、使用場景 apk升級,節省服務器和用戶的流量 二、原理 自從 Android 4.1 開始, Google Play 引入了應用程序的增量更新功能,App使用該升級方式,可節省約2/3

Android開發布局文件裏實現OnClick事件關聯處理方法

intent dsm nbsp ext 關聯 you vertica findview 時間 一般監聽OnClickListener事件,我們都是通過Button button = (Button)findViewById(....); button.se

Android 開發 ---- bootloader (LK)

ttl tab 不同的 opera 指定 isa system void mem LK是什麽 LK 是 Little Kernel 它是 appsbl (Applications ARM Boot Loader)流程代碼 ,little kernel

Android開發藍牙連接打印機

cep sdi tco disable ner gis util receiver count 代碼很簡單,直接一個布局文件和一個activity。需要的朋友可以直接將這兩部分粘貼復制到項目中即可。 Activity部分: package com.anhua.bluet

Android開發新建項目報錯的問題

instr rul txt gin 通過 ini .com org top 通過android studio新建一個空項目。在新建完項目之後,gradle編譯會報錯。 發生問題的原因是build.gradle(Project:TopDialog)中: allproject

Android開發CriminalIntent項目開發(其一)

開發項目 1.0 enc 增加 委派 其他 date 應用 module 前言   這次的開發項目是一個叫做CriminalIntent的應用,該應用可以詳細記錄各種辦公室陋習。這個應用記載的陋習記錄包括標題、日期和圖片,支持在聯系人中查找當事人,通過E-mail、Twit

Android開發旅3:android架構

通過 圖集 例如 sqlit 組件 mil 大小 簡化 .html 引言 通過前面兩篇: Android 開發之旅:環境搭建及HelloWorld Android 開發之旅:HelloWorld項目的目錄結構 我們對android有了個大

Android開發旅1:環境搭建及HelloWorld

lan 及其 其它 ply 新項目 bsp 驗證 for 對話框 ——工欲善其事必先利其器 引言 本系列適合0基礎的人員,因為我就是從0開始的,此系列記錄我步入Android開發的一些經驗分享,望與君共勉!作為Android隊伍中的一個新人的