日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

基于Android的浮动组件,可以用于应用中的新功能展示等等。

發布時間:2025/5/22 Android 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于Android的浮动组件,可以用于应用中的新功能展示等等。 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

在開發Android應用時,加新功能是必不可少的,我們加入了新的功能,有的一看界面就可以看出來,但是有的新功能就比較隱蔽,也就是用戶很難知道你添加了這個新功能,這個時候就需要用戶在打開我們的應用時給出一些提示,說明我們在哪里添加了新功能,點擊哪里可以看到這個新功能。這時我們第一時間想到的可能是Toast,因為它用法簡單,又不影響用戶操作,但是它有個缺點,就是不能明確的指示是哪里添加了新功能,除非你用文字描述出來。為此,我基于Toast編寫了一個小組件FloatTextToast(下面遇到的這個名字代替我寫的這個組件),他和Toast的用法一樣簡單,并且彌補了Toast的缺點,也更顯得更好看。

效果圖


你可以學到


  • Toast的基本用法
  • Android的消息機制,如何創建自己的消息隊列
  • 怎樣在Activity啟動時獲取一個View的width、height、top、left等屬性
  • 基本思路


  • 首先你要有一個處理好的9 PNG的圖片,用于自適應文字顯示,關于9 PNG處理可以參考Android Doc
  • 要顯示在哪個View的下面,就要知道這個目標View的位置
  • 把要顯示的文本放在一個TextView里,使用Toast的setView方法設置Toast要顯示的View。
  • 根據得到的位置,最后就是使用Toast的setGravity方法把要顯示的內容放到正確的位置顯示出來即可。
  • 總的來說首先就是要知道目標View,根據targetView計算出要顯示提示的位置,然后根據位置使用Toast把提示的文本顯示出來。但是這里有幾個難點,下面就一一解決

    Activity加載完成時獲取targetVIew的寬高和位置屬性


    我們加入了新的功能提示,自然會在用戶打開這個界面的時候就提示,但是在UI沒有渲染完成綁定倒Window上的時候,是不能獲取倒targetView的width、height和position的,那么我們怎么才能知道targetView的這些屬性呢?Activity的onAttachedToWindow回調方法是不能用的,況且它是在API 5加上的,以前的API中并沒有。不過我們還有一種方法,那就是在顯示提示的時候獲取targetView的屬性,如果獲取不到(為0)就一直獲取,直到獲取到為止,這其實是一個輪詢。為了達到這一目的,我們在開發者調用FloatTextToast.show()的時候使用Android的Message機制輪詢獲取一個targetView的屬性,如果獲取到,就會顯示提示文字了。在此之前先看下FloatTextToast構造函數,可以對它有個大概的了解,防止后面的代碼中出現的成員變量不認識。 [java] view plaincopyprint?
  • private?FloatTextToast(Context?context,View?targetView)?{??
  • ????????this.mTargetView?=?targetView;??
  • ????????this.mContext=?context;??
  • ????????mToast=new?Toast(mContext);??
  • ????????mContentView=new?TextView(mContext);??
  • ????????mContentView.setBackgroundResource(R.drawable.float_text_toast_bg);??
  • ????????mContentView.setTextColor(Color.BLACK);??
  • ????????mContentView.setTextSize(TypedValue.COMPLEX_UNIT_DIP,16);??
  • ????????mToast.setView(mContentView);??
  • ??????????
  • ????????//初始化一個Handler線程 ??
  • ????????mHandlerThread=new?HandlerThread("FloatTextToast");??
  • ????????mHandlerThread.start();??
  • ????????mHandler=new?FloatTextToastHandler(mHandlerThread.getLooper());??
  • ????}??
  • private FloatTextToast(Context context,View targetView) { this.mTargetView = targetView; this.mContext= context; mToast=new Toast(mContext); mContentView=new TextView(mContext); mContentView.setBackgroundResource(R.drawable.float_text_toast_bg); mContentView.setTextColor(Color.BLACK); mContentView.setTextSize(TypedValue.COMPLEX_UNIT_DIP,16); mToast.setView(mContentView); //初始化一個Handler線程 mHandlerThread=new HandlerThread("FloatTextToast"); mHandlerThread.start(); mHandler=new FloatTextToastHandler(mHandlerThread.getLooper()); }

    自定義自己的消息循環機制

    要想在一個自定義的組件中使用Message機制,一定要有自己的Looper機制,我們不能使用Activity的Looper,因為主Looper可能會有其他的Message需要處理,這就會導致我們的show方法會延遲調用,這樣效果就不好了,所以要有一個專門的Looper來處理此Message。要聲明自己的Looper,就需要HandlerThread這個類的配合了,這可是個好東西,使用它你會很容易的創建一個自己的線程用于處理你Message。使用方法很簡單,如下代碼: [java] view plaincopyprint?
  • //初始化一個Handler線程 ??
  • ????????mHandlerThread=new?HandlerThread("FloatTextToast");??
  • ????????mHandlerThread.start();??
  • ????????mHandler=new?FloatTextToastHandler(mHandlerThread.getLooper());??
  • //初始化一個Handler線程 mHandlerThread=new HandlerThread("FloatTextToast"); mHandlerThread.start(); mHandler=new FloatTextToastHandler(mHandlerThread.getLooper());
    這樣就聲明了一個HandlerThread并且讓它運行,運行之后我們就可以獲取一個屬于該Thread的Looper,然后把Message發送給這個Looper,那么這個線程就可以處理你發送的消息了。。看看我們的自定義Handler [java] view plaincopyprint?
  • private?class?FloatTextToastHandler?extends?Handler{??
  • ??
  • ????????public?FloatTextToastHandler(Looper?looper)?{??
  • ????????????super(looper);??
  • ????????}??
  • ??
  • ????????@Override??
  • ????????public?void?handleMessage(Message?msg)?{??
  • ????????????switch(msg.what){??
  • ????????????case?WHAT_SHOW:??
  • ????????????????showInHandler();??
  • ????????????}??
  • ????????}??
  • ??????????
  • ??????????
  • ????}??
  • private class FloatTextToastHandler extends Handler{ public FloatTextToastHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch(msg.what){ case WHAT_SHOW: showInHandler(); } } }
    它需要傳遞一個Looper作為構造參數聲明,意思就是使用這個Looper處理我發send的Message的意思。上面的代碼 [java] view plaincopyprint?
  • mHandler=new?FloatTextToastHandler(mHandlerThread.getLooper());??
  • mHandler=new FloatTextToastHandler(mHandlerThread.getLooper());
    正是我們使用自己開啟的線程處理我們的Message的意思。下面看下我們的showInHandler()方法是怎么處理的。 [java] view plaincopyprint?
  • /**在Handler調用的show方法,主要為了等待{@link?#mTargetView}的位置*/??
  • ????private?void?showInHandler(){??
  • ????????int[]?targetPos=getTargetViewPos();??
  • ????????if(targetPos[0]==0&&targetPos[1]==0){??
  • ????????????mHandler.sendEmptyMessageDelayed(WHAT_SHOW,?100);??
  • ????????}else{??
  • ????????????final?Rect?contentPos=getContentViewPos(targetPos);??
  • ????????????mToast.setGravity(Gravity.LEFT|Gravity.TOP,?contentPos.left,?contentPos.top);??
  • ????????????mToast.show();??
  • ????????}??
  • ????}??
  • /**在Handler調用的show方法,主要為了等待{@link #mTargetView}的位置*/ private void showInHandler(){ int[] targetPos=getTargetViewPos(); if(targetPos[0]==0&&targetPos[1]==0){ mHandler.sendEmptyMessageDelayed(WHAT_SHOW, 100); }else{ final Rect contentPos=getContentViewPos(targetPos); mToast.setGravity(Gravity.LEFT|Gravity.TOP, contentPos.left, contentPos.top); mToast.show(); } }
    該方法其實就是在獲取targetVIew的位置,如果獲取不到,則向自定義的Looper里發送一個Message重新調用該函數,如果得到了位置,那么就調用Toast的setGravity方法設置好要顯示文本的位置,然后顯示即可。

    獲取要顯示文本的位置

    要獲取顯示的位置,就要知道targetVIew的位置以及它的寬、高,這樣就能計算要顯示文本的位置了。View組件都有一個函數,可以把自己在Window里的坐標轉換為一個數組。 [java] view plaincopyprint?
  • private?int[]?getTargetViewPos(){??
  • ????????final?int[]?targetPos=new?int[2];??
  • ????????mTargetView.getLocationInWindow(targetPos);??
  • ????????return?targetPos;??
  • ????}??
  • private int[] getTargetViewPos(){ final int[] targetPos=new int[2]; mTargetView.getLocationInWindow(targetPos); return targetPos; }這樣,就返回了targetView的xy坐標了。光有targetView的坐標還不夠,還要有contentView最終要顯示的位置。 [java] view plaincopyprint?
  • /**?
  • ?????*?計算獲取浮動文本顯示的位置,把浮動文本放在targetView的中心處?
  • ?????*?@return?一個包含top和left的Rect?
  • ?????*/??
  • ????private??Rect?getContentViewPos(int[]?targetPos){??
  • ????????final?Rect?windowVisibleRect=new?Rect();??
  • ????????final?View?targetView=mTargetView;??
  • ????????final?TextView?contentView=mContentView;??
  • ????????//狀態欄高度 ??
  • ????????targetView.getWindowVisibleDisplayFrame(windowVisibleRect);??
  • ????????int?statusBarHeight=windowVisibleRect.top;??
  • ??????????
  • ????????//背景圖那個三角箭頭的位置 ??
  • ????????final?TextPaint?textPaint=contentView.getPaint();??
  • ????????int?contentW=(int)textPaint.measureText((String)contentView.getText());??
  • ????????int?arrowPos=(int)(contentW*(30.0/160));??
  • ??????????
  • ????????final?Rect?rect?=?new?Rect();??
  • ????????rect.left?=?targetPos[0]+targetView.getWidth()/2-arrowPos;??
  • ????????rect.top?=?targetPos[1]-statusBarHeight?+?targetView.getHeight();??
  • ????????return?rect;??
  • ????}??
  • /** * 計算獲取浮動文本顯示的位置,把浮動文本放在targetView的中心處 * @return 一個包含top和left的Rect */ private Rect getContentViewPos(int[] targetPos){ final Rect windowVisibleRect=new Rect(); final View targetView=mTargetView; final TextView contentView=mContentView; //狀態欄高度 targetView.getWindowVisibleDisplayFrame(windowVisibleRect); int statusBarHeight=windowVisibleRect.top; //背景圖那個三角箭頭的位置 final TextPaint textPaint=contentView.getPaint(); int contentW=(int)textPaint.measureText((String)contentView.getText()); int arrowPos=(int)(contentW*(30.0/160)); final Rect rect = new Rect(); rect.left = targetPos[0]+targetView.getWidth()/2-arrowPos; rect.top = targetPos[1]-statusBarHeight + targetView.getHeight(); return rect; }
    這個函數的功能就是讓文本顯示在targetView的下方的橫向中間的位置,也就是文本的背景尖角三角要指向targetView橫向中間的位置,這樣才好看些。為了這個才需要使用Paint測量文本的寬度,所以這也是該組件的一個缺陷,不能顯示String格式之外的字符,比如SpannableString。

    完整的組件代碼


    上面是對組件代碼的拆分講解,是為了說明我們當時實現這個組件的想法以及步驟,下面就整體把代碼列出來,明了的看一下。 [java] view plaincopyprint?
  • /**?
  • ?*?浮動的文本顯示。根據一個提供的View,可以把文本顯示到該View的下面.?
  • ?*?可以設置顯示的時間,多了該時間后自動消失。目前只支持純文本{@link?String}類型的顯示?
  • ?*?因為要計算顯示文本的寬度。?
  • ?*?@author?michael_li(飛雪無情)?
  • ?*?@since?2011-12-10?下午04:57:36?
  • ?*/??
  • public?class?FloatTextToast?{??
  • ????public?static?final?int?LENGTH_LONG=Toast.LENGTH_LONG;??
  • ????public?static?final?int?LENGTH_SHORT=Toast.LENGTH_SHORT;??
  • ????private?static?final?int?WHAT_SHOW=1;??
  • ??????
  • ????private?Context?mContext;??
  • ????private?View?mTargetView;??
  • ????private?Toast?mToast;??
  • ????private??TextView?mContentView;??
  • ??????
  • ????private?HandlerThread?mHandlerThread;??
  • ????private?FloatTextToastHandler?mHandler;??
  • ????private?FloatTextToast(Context?context,View?targetView)?{??
  • ????????this.mTargetView?=?targetView;??
  • ????????this.mContext=?context;??
  • ????????mToast=new?Toast(mContext);??
  • ????????mContentView=new?TextView(mContext);??
  • ????????mContentView.setBackgroundResource(R.drawable.float_text_toast_bg);??
  • ????????mContentView.setTextColor(Color.BLACK);??
  • ????????mContentView.setTextSize(TypedValue.COMPLEX_UNIT_DIP,16);??
  • ????????mToast.setView(mContentView);??
  • ??????????
  • ????????//初始化一個Handler線程 ??
  • ????????mHandlerThread=new?HandlerThread("FloatTextToast");??
  • ????????mHandlerThread.start();??
  • ????????mHandler=new?FloatTextToastHandler(mHandlerThread.getLooper());??
  • ????}??
  • ????/**?
  • ?????*?生成一個FloatTextToast?
  • ?????*?@param?context?Activity?上下文?
  • ?????*?@param?targetView??目標View,浮動文本要顯示在哪個View下面?
  • ?????*?@param?text?要顯示的文本?
  • ?????*?@param?duration?浮動文本顯示的時間?{@link?#LENGTH_LONG}?{@link?#LENGTH_SHORT}?
  • ?????*?@return?一個FloatTextToast,可以調用{@link?#show()}顯示?
  • ?????*/??
  • ????public?static?FloatTextToast?makeText(Context?context,View?targetView,?String?text,?int?duration)?{??
  • ????????final?FloatTextToast?floatToast=new?FloatTextToast(context,targetView);??
  • ????????final?TextView?contentView=floatToast.mContentView;??
  • ????????contentView.setText(text);??
  • ????????floatToast.mToast.setDuration(duration);??
  • ????????return?floatToast;??
  • ????}??
  • ????/**?
  • ?????*?顯示浮動文本?
  • ?????*/??
  • ????public?void?show(){??
  • ????????mHandler.sendEmptyMessage(WHAT_SHOW);??
  • ????}??
  • ????/**在Handler調用的show方法,主要為了等待{@link?#mTargetView}的位置*/??
  • ????private?void?showInHandler(){??
  • ????????int[]?targetPos=getTargetViewPos();??
  • ????????if(targetPos[0]==0&&targetPos[1]==0){??
  • ????????????mHandler.sendEmptyMessageDelayed(WHAT_SHOW,?100);??
  • ????????}else{??
  • ????????????final?Rect?contentPos=getContentViewPos(targetPos);??
  • ????????????mToast.setGravity(Gravity.LEFT|Gravity.TOP,?contentPos.left,?contentPos.top);??
  • ????????????mToast.show();??
  • ????????}??
  • ????}??
  • ????private?int[]?getTargetViewPos(){??
  • ????????final?int[]?targetPos=new?int[2];??
  • ????????mTargetView.getLocationInWindow(targetPos);??
  • ????????return?targetPos;??
  • ????}??
  • ????/**?
  • ?????*?計算獲取浮動文本顯示的位置,把浮動文本放在targetView的中心處?
  • ?????*?@return?一個包含top和left的Rect?
  • ?????*/??
  • ????private??Rect?getContentViewPos(int[]?targetPos){??
  • ????????final?Rect?windowVisibleRect=new?Rect();??
  • ????????final?View?targetView=mTargetView;??
  • ????????final?TextView?contentView=mContentView;??
  • ????????//狀態欄高度 ??
  • ????????targetView.getWindowVisibleDisplayFrame(windowVisibleRect);??
  • ????????int?statusBarHeight=windowVisibleRect.top;??
  • ??????????
  • ????????//背景圖那個三角箭頭的位置 ??
  • ????????final?TextPaint?textPaint=contentView.getPaint();??
  • ????????int?contentW=(int)textPaint.measureText((String)contentView.getText());??
  • ????????int?arrowPos=(int)(contentW*(30.0/160));??
  • ??????????
  • ????????final?Rect?rect?=?new?Rect();??
  • ????????rect.left?=?targetPos[0]+targetView.getWidth()/2-arrowPos;??
  • ????????rect.top?=?targetPos[1]-statusBarHeight?+?targetView.getHeight();??
  • ????????return?rect;??
  • ????}??
  • ????private?class?FloatTextToastHandler?extends?Handler{??
  • ??
  • ????????public?FloatTextToastHandler(Looper?looper)?{??
  • ????????????super(looper);??
  • ????????}??
  • ??
  • ????????@Override??
  • ????????public?void?handleMessage(Message?msg)?{??
  • ????????????switch(msg.what){??
  • ????????????case?WHAT_SHOW:??
  • ????????????????showInHandler();??
  • ????????????}??
  • ????????}??
  • ??????????
  • ??????????
  • ????}??
  • }??
  • /** * 浮動的文本顯示。根據一個提供的View,可以把文本顯示到該View的下面. * 可以設置顯示的時間,多了該時間后自動消失。目前只支持純文本{@link String}類型的顯示 * 因為要計算顯示文本的寬度。 * @author michael_li(飛雪無情) * @since 2011-12-10 下午04:57:36 */ public class FloatTextToast { public static final int LENGTH_LONG=Toast.LENGTH_LONG; public static final int LENGTH_SHORT=Toast.LENGTH_SHORT; private static final int WHAT_SHOW=1; private Context mContext; private View mTargetView; private Toast mToast; private TextView mContentView; private HandlerThread mHandlerThread; private FloatTextToastHandler mHandler; private FloatTextToast(Context context,View targetView) { this.mTargetView = targetView; this.mContext= context; mToast=new Toast(mContext); mContentView=new TextView(mContext); mContentView.setBackgroundResource(R.drawable.float_text_toast_bg); mContentView.setTextColor(Color.BLACK); mContentView.setTextSize(TypedValue.COMPLEX_UNIT_DIP,16); mToast.setView(mContentView); //初始化一個Handler線程 mHandlerThread=new HandlerThread("FloatTextToast"); mHandlerThread.start(); mHandler=new FloatTextToastHandler(mHandlerThread.getLooper()); } /** * 生成一個FloatTextToast * @param context Activity 上下文 * @param targetView 目標View,浮動文本要顯示在哪個View下面 * @param text 要顯示的文本 * @param duration 浮動文本顯示的時間 {@link #LENGTH_LONG} {@link #LENGTH_SHORT} * @return 一個FloatTextToast,可以調用{@link #show()}顯示 */ public static FloatTextToast makeText(Context context,View targetView, String text, int duration) { final FloatTextToast floatToast=new FloatTextToast(context,targetView); final TextView contentView=floatToast.mContentView; contentView.setText(text); floatToast.mToast.setDuration(duration); return floatToast; } /** * 顯示浮動文本 */ public void show(){ mHandler.sendEmptyMessage(WHAT_SHOW); } /**在Handler調用的show方法,主要為了等待{@link #mTargetView}的位置*/ private void showInHandler(){ int[] targetPos=getTargetViewPos(); if(targetPos[0]==0&&targetPos[1]==0){ mHandler.sendEmptyMessageDelayed(WHAT_SHOW, 100); }else{ final Rect contentPos=getContentViewPos(targetPos); mToast.setGravity(Gravity.LEFT|Gravity.TOP, contentPos.left, contentPos.top); mToast.show(); } } private int[] getTargetViewPos(){ final int[] targetPos=new int[2]; mTargetView.getLocationInWindow(targetPos); return targetPos; } /** * 計算獲取浮動文本顯示的位置,把浮動文本放在targetView的中心處 * @return 一個包含top和left的Rect */ private Rect getContentViewPos(int[] targetPos){ final Rect windowVisibleRect=new Rect(); final View targetView=mTargetView; final TextView contentView=mContentView; //狀態欄高度 targetView.getWindowVisibleDisplayFrame(windowVisibleRect); int statusBarHeight=windowVisibleRect.top; //背景圖那個三角箭頭的位置 final TextPaint textPaint=contentView.getPaint(); int contentW=(int)textPaint.measureText((String)contentView.getText()); int arrowPos=(int)(contentW*(30.0/160)); final Rect rect = new Rect(); rect.left = targetPos[0]+targetView.getWidth()/2-arrowPos; rect.top = targetPos[1]-statusBarHeight + targetView.getHeight(); return rect; } private class FloatTextToastHandler extends Handler{ public FloatTextToastHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch(msg.what){ case WHAT_SHOW: showInHandler(); } } } } 此組件和Toast的實現方法一樣,所以上手不難,只需使用makeText靜態方法生成一個即可 [java] view plaincopyprint?
  • FloatTextToast.makeText(Context?context,?View?targetView,?String?text,?int?duration).show()??
  • FloatTextToast.makeText(Context context, View targetView, String text, int duration).show()就這么簡單,傳進去幾個參數,show出即可,和Toast一樣好用。

    小結


    這里主要是通過類之間的組合編寫一個一個FloatTextToast組件,便于在應用中提示一些信息,不光局限于新功能的提示,還有其他的點擊查看個人信息等等,就如上面的效果圖一樣。這里主要的難點就在于Activity啟動獲取targetView的狀態,這里采用了不受影響的自定義的消息機制,能及時的獲取targetView的狀態。這里也采用的Toast的隊列機制,這樣就能夠更好的一個個的提示,讓用戶看完一個再顯示另外一個,不至于一下子全顯示出來,而用戶沒有時間看。這里還采用了Paint用于測量文本的真實寬度,所以也有了一些缺陷,如果哪位有更好的方法,也可以留言告知我,不勝感激。
    附上組件源代碼和效果圖的Demo下載?http://download.csdn.net/detail/michael__li/3904636

    轉載于:https://www.cnblogs.com/zhwl/archive/2012/03/17/2402863.html

    總結

    以上是生活随笔為你收集整理的基于Android的浮动组件,可以用于应用中的新功能展示等等。的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。