先上效果图:

之前用手机QQ时,一直很觉得这个窗口提示挺不错的,今天将它大概地实现了一遍。

首先是:提示窗口的三角下标是可以改变位置的,然后窗口中有很多小的item,item被点击时会显示出不同的颜色,

同时三角下标的颜色也随着改变。

然后是:提示窗口的item们会根据传入的坐标实现向上显示或向下显示。

一、对TipView定义一些成员变量

// 一些状态变量
private static final int STATUS_DOWN = 1;
private static final int STATUS_UP = 2;
// 初始窗口的Item显示在上方
private int mStatus = STATUS_UP;// Item之间的分隔线的颜色
private int mSeparateLineColor ;// 窗口边上两个方块的边角半径大小
private int mCorner = dip2px(6);private Paint mPaint; // 画方块和文字的画笔
private Paint doPaint; // 画三角下标的画笔private Path mPath; // 绘制的路径private int mBorderMargin = dip2px(5); // 提示窗口与屏幕(根布局)的最小距离
private int mItemWidth = dip2px(50); // 窗口Item的宽度
private int mItemHeight = dip2px(48); // 窗口Item的高度
private int mTriangleTop = dip2px(50); // 三角下标的顶点
private int mHalfTriangleWidth = dip2px(6); // 三角小标的半宽
private int mItemBorder; // 三角小标与窗口Item的临界
private int realLeft; // 窗口的left值private List<TipItem> mItemList = new ArrayList<>(); // 存储每个Item的信息
private List<Rect> mItemRectList = new ArrayList<>(); // 存储每个方块的信息private OnItemClickListener onItemClickListener; // Item点击接口
private int choose = -1; // 是否有Item被按下,是为Item的序号,否为-1// 外界传入的点击坐标x、y
private int x;
private int y;

二、TipView的初始化

TipView的构造方法:

public TipView(Context context, ViewGroup rootView,int x,int y,List<TipItem> mItemList) {super(context);this.x = x; // 设置传入过来的x轴坐标this.y = y;  // 设置传入过来的y轴坐标// x和y决定了三角下标的位置initPaint(); // 初始化画笔setTipItemList(mItemList); // 初始化Item集合,并对Item的字符串长度进行处理//【当字符串过长时,使用后端省略处理:“xxx...”】addView(rootView); // 将TipView实例添加到传入的rootView中。// 注意:rootView需要FrameLayout/RelativeLayout或其子类实例initView(); // 根据传入的点击坐标x、y进行状态判断和最左位置的处理
}

initView()的具体实现:主要对临界情况的一些值得处理

private void initView() {// 获取屏幕宽度int mScreenWidth = getResources().getDisplayMetrics().widthPixels;// 当点击事件的纵坐标y比较小时(点击的位置比较上面)if (y/2<mItemHeight) {mStatus = STATUS_DOWN; // 令窗口在下方显示mTriangleTop = y + dip2px(5); // 设置三角下标的顶点mItemBorder = mTriangleTop + dip2px(6); // 设置三角下标和窗口方块的交界处} else {mStatus = STATUS_UP;   // 同理如上mTriangleTop = y - dip2px(5);mItemBorder = mTriangleTop - dip2px(6);}// 获取当Item数量两边对称时,窗口的left值:realLeft = x - (mItemWidth * mItemList.size()) / 2;if (realLeft < 0) {// 跑出屏幕左边的话,令窗口的left值为距离值realLeft = mBorderMargin;// 防止三角下标与方块分离if(x-mCorner<=realLeft) x = realLeft+mCorner*2;} else if (realLeft + (mItemWidth*mItemList.size()) > mScreenWidth) {// 跑出屏幕右边的话,则减去溢出的宽度,再减去距离值realLeft -= realLeft + (mItemWidth*mItemList.size())-mScreenWidth+mBorderMargin;// 防止三角下标与方块分离if(x+mCorner>=realLeft+mItemWidth*mItemList.size()) x =  realLeft+mItemWidth*mItemList.size()-mCorner*2;}// 没有对窗口左右边都超出的情况做处理,大家有没有好的解决方案?}

三、TipView的绘制

首先绘制图层为透明,再根据判断得来的状态绘制窗口。

@Override
protected void onDraw(Canvas canvas) {super.onDraw(canvas);drawBackground(canvas);switch (mStatus) {case STATUS_DOWN:drawItemDown(canvas);break;case STATUS_UP:drawItemUp(canvas);break;default:break;}
}

具体绘制各个窗口方块的代码太长不便贴出,可参考源码及其注释。

大致的流程就是

a. 绘制最左方块、最右方块和中间方块
b. 根据方块是否被点击而更换不同的颜色来绘制方块
c. 绘制分隔线

四、TipView中的Item点击事件的监听

设计一个监听器接口:

public interface OnItemClickListener {// 设计两个参数void onItemClick(String name,int position);void dismiss();
}

覆写TipView的onTouchEvent方法:

@Override
public boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:for (int i = 0; i < mItemRectList.size(); i++) {if (onItemClickListener != null && isPointInRect(new PointF(event.getX(), event.getY()), mItemRectList.get(i))) {// 被按下时,choose值为当前方块Item序号choose = i;// 更新视图postInvalidate(mItemRectList.get(i).left,mItemRectList.get(i).top,mItemRectList.get(i).right,mItemRectList.get(i).bottom);}}return true;case MotionEvent.ACTION_UP:for (int i = 0; i < mItemRectList.size(); i++) {if (onItemClickListener != null && isPointInRect(new PointF(event.getX(), event.getY()), mItemRectList.get(i))) {// 触发方法,传入两个参数onItemClickListener.onItemClick(mItemList.get(i).getTitle(),i);choose = -1;}}if (onItemClickListener != null) {onItemClickListener.dismiss(); // 触发方法}removeView(); // 移除TipViewreturn true;}return true;
}

五、以Build模式为设计模式:

public static class Builder {// TipView中一些重要的成员变量private OnItemClickListener onItemClickListener;private Context mContext;private ViewGroup mRootView; private List<TipItem> mTipItemList = new ArrayList<>();private int mSeparateLineColor = Color.WHITE;private int x ,y;public Builder(Context context, ViewGroup rootView,int x,int y) {mContext = context;mRootView = rootView;this.x = x;this.y = y;}public Builder addItem(TipItem tipItem) {mTipItemList.add(tipItem);return this;}public Builder addItems(List<TipItem> list) {mTipItemList.addAll(list);return this;}public Builder setSeparateLineColor(int color) {mSeparateLineColor = color;return this;}public Builder setOnItemClickListener(OnItemClickListener onItemClickListener){this.onItemClickListener = onItemClickListener;return this;}// 创建TipView实例public TipView create() {TipView flipShare = new TipView(mContext, mRootView,x,y,mTipItemList);flipShare.setOnItemClickListener(onItemClickListener);flipShare.setSeparateLineColor(mSeparateLineColor);return flipShare;}}

六、使用示例:

创建TipView实例时,需要传入控件被点击或长按时的位置坐标。

使用注意:传给rootView的参数需要FrameLayout / RelativeLayout或其子类实例,这样TipView对象才可以悬浮地显示出来。

public class MainActivity extends AppCompatActivity {private Button button0;private RelativeLayout rl;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);button0 = (Button) findViewById(R.id.button0);rl = (RelativeLayout) findViewById(R.id.activity_main);button0.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {int x = 0;int y = 0;if(event.getAction()==MotionEvent.ACTION_UP){// 获取点击位置x= (int) event.getX();y = (int) event.getY();Log.i("zz",x+"  "+y);// 传入视图上的坐标TipView share = new TipView.Builder(MainActivity.this,rl,x+v.getLeft(),y+v.getTop()).addItem(new TipItem("复制复制")).addItem(new TipItem("粘贴")).addItem(new TipItem("删除")).addItem(new TipItem("收藏")).addItem(new TipItem("转发")).addItem(new TipItem("更多")).setOnItemClickListener(new TipView.OnItemClickListener() {@Overridepublic void onItemClick(String str,int a) {Toast.makeText(MainActivity.this,str,Toast.LENGTH_SHORT).show();}@Overridepublic void dismiss() {}}).create();}return true;}});}}

效果图Demo:Github

参考:

https://github.com/JeasonWong/FlipShare

安卓开发之自定义控件TipView仿QQ长按后的提示窗口相关推荐

  1. 安卓自定义日期控件(仿QQ,IOS7)

    还记得上篇:高大上的安卓日期时间选择器,本篇是根据上篇修改而来,先看下qq中日期选择的效果: 鉴于目前还没有相似的开源日期控件,因此本人花费了一些时间修改了下之前的日期控件,效果如图: 虽说相似度不是 ...

  2. 安卓开发裕语言程序---调用qq收藏作为远程更新实例

    安卓开发&裕语言程序---调用qq收藏作为远程更新实例 在裕语言环境下,做安卓个人开发的过程中,我们时有需要在软件内部实现动态远程公告更新,如果不采用传统方法,而改用QQ收藏来做,那么,如何实 ...

  3. java如何开发游戏大厅_java仿qq游戏大厅的设计与实现

    摘要:由于生活节奏的越来越快,人们越来越少的外出游玩.现在的人们为了生活,为了工作,为了家庭无时无刻不在紧张的环境中度过.而一些简单的小游戏则成为了人们放松的主要方式,本文用java语言开发了客户端/ ...

  4. c#开发的漂亮高仿QQ打包安装程序界面

    c#开发的触摸屏打包安装程序:仿QQ登录密码输入框.自定义软件键盘:c#开发的仿QQ2013界面用户美化打包程序:整个程序使用vs2010开发:支持所有程序打包安装:源代码开放,可自己修改效果图如下: ...

  5. QQ空间对图片的处理之仿QQ长图预览

    不知各位遇到特别长的图片时是怎么处理的? 是 截取符合长宽的部分做临时展示? 还是 硬要长宽100%模糊(啥也看不清)展示? 还是 先拿一个压缩的图片做占位,在鼠标移入或点击时放大预览? 今天偶然打开 ...

  6. 安卓开发_自定义控件_界面的简单侧滑

    主界面 package com.itheima.news;import android.os.Bundle; import android.app.Activity; import android.v ...

  7. 安卓自定义日期控件(仿QQ,IOS7)续

    本篇是在原来的基础上修改了界面效果,使其更加接近ios7,qq等日期选择控件,看图: 源码地址:http://download.csdn.net/detail/baiyuliang2013/87601 ...

  8. android qq音乐布局,仿QQ音乐底部栏

    最近在开发一款高仿QQ音乐播放器的Demo,遇到了一个问题,在QQ音乐主界面有一个常驻底部栏,底部栏中有一个可左右滑动切歌的组件,最后还是实现了效果,今天来回顾一下实现过程. 要实现的就是最下方的常驻 ...

  9. 安卓开发学习1:安卓开发资源与方法总结

    开发工具 Android Studio下载 Genymotion 下载 Android Studio配置 Android Studio的Gradle配置国内镜像 Android Studio配置代码提 ...

最新文章

  1. 【读书笔记】知易行难,多实践
  2. Servlet 请求的转发
  3. 关于“编程的本质”的探讨
  4. ios 超签签名服务器搭建(超签)
  5. java写一个外网访问的接口_【JAVA基础】一个案例搞懂类、对象、重载、封装、继承、多态、覆盖、抽象和接口概念及区别(中篇)...
  6. pythonmysql数据分析 tableau_python执行mysql 计算复购率+pyechart+Excel+Tableau绘制双Y轴图...
  7. 三步修改CodeBlocks主题
  8. Javascript 5 种原始数据类型
  9. 前端学习(2730):重读vue电商网站40之使用vue-table-with-tree-grid
  10. tornado学习笔记day07-同步与异步
  11. H5获取html标签
  12. ValueError: This sheet is too large! Your sheet size
  13. LOJ2181 排序
  14. 计算机上机操作表格试题,全国计算机等级考试四Excel电子表格操作试题.doc
  15. ROS 发布消息和订阅消息 for Python
  16. iOS 消息转发(Message Forwarding)
  17. 中关村企业 大数据_中关村大数据企业产业规模年均增长20%以上
  18. hexo搭建博客的几种方式(入门级)
  19. android 开源_8个开源Android教育应用
  20. 5G进度卡关 联发科应如何解困?

热门文章

  1. html标题如何设置行书,四招打通行书之“气”
  2. 没学过python、但是还是有公司要-为什么自学Python看不进去?
  3. 怎么在php网站大图加倒计时,WordPress站点添加活动倒计时功能教程
  4. collect_set函数
  5. 【2022高考季】作为一个过来人想说的话
  6. 基于QT 实现机器视觉软件
  7. 调音台docker教程_Docker超详细教程
  8. STM32实例源码剖析(基于51单片机的摇摇棒制作)
  9. PHP经典乱码“锘”字与解决办法
  10. 利用Word 2010对书籍排版进行设置(三)--常用格式设置(1)