基于Android的浮动组件,可以用于应用中的新功能展示等等。
前言
效果图
你可以学到
- Toast的基本用法
- Android的消息机制,如何创建自己的消息队列
- 怎样在Activity启动时获取一个View的width、height、top、left等属性
基本思路
- 首先你要有一个处理好的9 PNG的图片,用于自适应文字显示,关于9 PNG处理可以参考Android Doc
- 要显示在哪个View的下面,就要知道这个目标View的位置
- 把要显示的文本放在一个TextView里,使用Toast的setView方法设置Toast要显示的View。
- 根据得到的位置,最后就是使用Toast的setGravity方法把要显示的内容放到正确的位置显示出来即可。
Activity加载完成时获取targetVIew的宽高和位置属性
- 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()); }
自定义自己的消息循环机制
- //初始化一个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
- 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的意思。上面的代码
- mHandler=new FloatTextToastHandler(mHandlerThread.getLooper());
mHandler=new FloatTextToastHandler(mHandlerThread.getLooper());
正是我们使用自己开启的线程处理我们的Message的意思。下面看下我们的showInHandler()方法是怎么处理的。
- /**在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方法设置好要显示文本的位置,然后显示即可。
获取要显示文本的位置
- 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最终要显示的位置。
- /**
- * 计算获取浮动文本显示的位置,把浮动文本放在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。
完整的组件代码
- /**
- * 浮动的文本显示。根据一个提供的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(); } } } }
- FloatTextToast.makeText(Context context, View targetView, String text, int duration).show()
FloatTextToast.makeText(Context context, View targetView, String text, int duration).show()就这么简单,传进去几个参数,show出即可,和Toast一样好用。
小结
转载于:https://www.cnblogs.com/zhwl/archive/2012/03/17/2402863.html
基于Android的浮动组件,可以用于应用中的新功能展示等等。相关推荐
- 卡路里计算JAVA_pedometer 这是一个基于android平台的软件,用于计算你走路的步数,算出消耗的卡路里,以达到健 238万源代码下载...
详细说明:这是一个基于android平台的软件,用于计算你走路的步数,算出消耗的卡路里,以达到健康的管理.-This is an android platform based software, us ...
- android开发收藏功能实现,Android使用Realm数据库如何实现App中的收藏功能
Android使用Realm数据库如何实现App中的收藏功能 发布时间:2021-05-07 11:20:34 来源:亿速云 阅读:63 作者:小新 这篇文章主要介绍了Android使用Realm数据 ...
- js php通讯录,基于aotu.js实现微信自动添加通讯录中的联系人功能
什么是Auto.JS? Auto.JS是Android平台上的JavaScript自动化工具. 它的本质是可执行自己编写的简易Javascript脚本的,尤其可以在开启"无障碍模式" ...
- chrome android 功能大全,Android版Chrome 55 大更新,多个新功能袭来
原标题:Android版Chrome 55 大更新,多个新功能袭来 前几天,发布了桌面版Chrome 55 稳定版,而今日Android版Chrome 55 也正式到来,相比之间只是性能优化和BUG修 ...
- android8.1新功能,EMUI 8.0 +Android 8.1 你可能从未见过的新功能!
原标题:EMUI 8.0 +Android 8.1 你可能从未见过的新功能! 被誉为国产机皇,唯一能叫板苹果的华为,在10月16日发布了旗下第一代搭载人工智能AI处理器芯片的手机,这款手机可以说是集齐 ...
- 基于android的网络音乐播放器-网络音乐的搜索和展示(五)
作为android初学者,最近把疯狂android讲义和疯狂Java讲义看了一遍,看到书中介绍的知识点非常多,很难全部记住,为了更好的掌握基础知识点,我将开发一个网络音乐播放器-EasyMusic来巩 ...
- Android 8.0 正式发布,Google 带来了哪些新功能?
文/屠敏 2017 年 8 月 21 日,随着日全食的到来,此前一直猜测是 OREO(奥利奥)还是 Orellete(加泰罗尼亚的点心)的 Android 8.0 最终拉开帷幕,Google 正式采取 ...
- birt预览能有内容发布后没内容_谷歌突然推出Android 11开发者预览版 新版带来部分新功能和改进...
谷歌刚刚在安卓开发者网站放出 Android 11 版的开发者预览版,该版本主要面向开发者提供用来测试新版功能. 在新版本里目前谷歌已经发布部分新功能和改进,随着开发者版本不断更迭后续更多新功能和改进 ...
- 谷歌不支持调用摄像头麦克风_谷歌突然推出Android 11开发者预览版 新版带来部分新功能和改进...
谷歌刚刚在安卓开发者网站放出 Android 11 版的开发者预览版,该版本主要面向开发者提供用来测试新版功能. 在新版本里目前谷歌已经发布部分新功能和改进,随着开发者版本不断更迭后续更多新功能和改进 ...
最新文章
- 苹果/三星/华为纷纷布局人工智能 将AI作为公司发展新动力
- 东芝收购协议达成 富士通正式退出硬盘市场
- 难点电路详解之负反馈放大器电路(1)
- linux sed错误sed: -e expression #1, unknown option to `s'解决办法
- cf451E. Devu and Flowers(产生不同多重集数量)
- 在eclipse中指定启动时java的位置
- javascript中的||运算符
- 美国太空部队加入美国情报系统,以确保太空的安全
- linux8如何开启多个桌面,CentOS8安装GNOME3桌面并设置开机启动图形界面
- 日志过滤工具 LogViewer Pro
- html按钮 字 颜色代码,html中按钮的字体颜色怎么设置?
- ‘字符型‘变量和‘字符串型‘变量
- 560套Axure低保真原型打包下载!各行各业产品经理、交互设计师必备资源库!!!
- PC游戏史上十大最经典RPG
- Metrics-server
- android activity pause,关于android:onPause()和onStop()在Activity中
- 2018 年 Google 设计亮点回顾
- 海尔微型计算机一键还原怎么操作,电脑的一键还原在哪_电脑一键还原详细教程_电脑一键还原怎么操作...
- udb和udbx的区别_DB2 UDB,WebSphere和iBATIS
- vue(4) - 收藏集 - 掘金