效果图:

原理:


控件源码:

public class DragView extends View {private int defaultZoomSize = 8;//初始化圆的大小private int initRadius;//圆1的圆心位置private PointF center1;private PointF center2;private PointF point1;private PointF point2;private PointF point3;private PointF point4;private int mWidth;private int mHeight;private float realZoomSize;private float currentRadius;private float minRadiusScale = 1 / 2f;private Paint paint;private Path path;private Bitmap bitmap;@DragStatusprivate int mDragStatus;public DragView(Context context) {this(context, null);}public DragView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public DragView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);paint = new Paint();paint.setColor(Color.BLUE);paint.setStyle(Paint.Style.FILL);paint.setStrokeWidth(4);paint.setAntiAlias(true);path = new Path();center1 = new PointF();center2 = new PointF();point1 = new PointF();point2 = new PointF();point3 = new PointF();point4 = new PointF();bitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.icon_pot);initRadius = Math.min(bitmap.getWidth(), bitmap.getHeight()) / 2;Log.e("zhen", "解析bitmap: " + bitmap.getWidth() + " * " + bitmap.getHeight() + " * " + initRadius);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);mWidth = w;mHeight = h;center1.set(mWidth / 2, mHeight / 2);Log.d("zhen", "圆心位置:x" + center1.x + " y: " + center1.y);}private boolean isSelected = false;@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX();float y = event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:if (Math.sqrt(Math.pow(x - center1.x, 2) + Math.pow(y - center1.y, 2)) < initRadius&& mDragStatus == DragStatus.NORMAL) {inAnimation = false;isSelected = true;Log.e("zhen", "选中状态");}break;case MotionEvent.ACTION_MOVE:if (isSelected) {
//                    Log.d("zhen", "拖动距离: " + dragDistance);if (mDragStatus != DragStatus.DRAG_BACK && mDragStatus != DragStatus.DRAG_TO) {mDragStatus = DragStatus.DRAG_MOVE;center2.set(x, y);float dragDistance = (float) (Math.sqrt(Math.pow(center2.x - center1.x, 2)+ Math.pow(center2.y - center1.y, 2)));//多少倍圆的大小realZoomSize = dragDistance / initRadius;invalidate();}}break;case MotionEvent.ACTION_UP:if (isSelected) {if (realZoomSize <= defaultZoomSize) {//回弹,改变center2.x, center2.y直到等于center1.x, center1.ydoAnimation(DragStatus.DRAG_BACK, center2, center1);}}isSelected = false;break;}return true;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//圆的半径改变currentRadius = initRadius * (1 + (minRadiusScale - 1) / defaultZoomSize * realZoomSize);if (realZoomSize > defaultZoomSize) {//圆缩小为一半,去往目的地,就应该消失了doAnimation(DragStatus.DRAG_TO, center1, center2);}//中间矩形
//        paint.setColor(Color.BLACK);float angle = (float) Math.atan((center2.y - center1.y) / (center2.x - center1.x));float sinValue;float cosValue;float controlX;float controlY;sinValue = (float) Math.abs((currentRadius * Math.sin(angle)));cosValue = (float) Math.abs((currentRadius * Math.cos(angle)));controlX = (center1.x + center2.x) / 2;controlY = (center1.y + center2.y) / 2;point1.set(center1.x - sinValue, center1.y - cosValue);point2.set(center1.x + sinValue, center1.y + cosValue);point3.set(center2.x - sinValue, center2.y - cosValue);point4.set(center2.x + sinValue, center2.y + cosValue);path.reset();switch (mDragStatus) {case DragStatus.NORMAL:currentRadius = initRadius;//原始图片canvas.drawBitmap(bitmap, center1.x - initRadius, center1.y - initRadius, paint);//起始位置的圆
//                paint.setColor(Color.RED);
//                canvas.drawCircle(center1.x, center1.y, currentRadius, paint);break;case DragStatus.DRAG_MOVE://拖动过程中path.moveTo(point1.x, point1.y);path.lineTo(point2.x, point2.y);path.quadTo(controlX, controlY, point4.x, point4.y);path.lineTo(point3.x, point3.y);path.quadTo(controlX, controlY, point1.x, point1.y);canvas.drawPath(path, paint);//起始位置的圆paint.setColor(Color.RED);canvas.drawCircle(center1.x, center1.y, currentRadius, paint);//结束位置的圆
//                paint.setColor(Color.BLUE);
//                canvas.drawCircle(center2.x, center2.y, currentRadius, paint);//原始图片canvas.drawBitmap(bitmap, center2.x - initRadius, center2.y - initRadius, paint);break;case DragStatus.DRAG_BACK://改变center2.x, center2.y直到等于center1.x, center1.ypath.reset();path.moveTo(point1.x, point1.y);path.quadTo(center2.x, center2.y, point2.x, point2.y);canvas.drawPath(path, paint);//起始位置的圆
//                paint.setColor(Color.RED);
//                canvas.drawCircle(center1.x, center1.y, currentRadius, paint);//原始图片canvas.drawBitmap(bitmap, center1.x - initRadius, center1.y - initRadius, paint);break;case DragStatus.DRAG_TO://改变center1.x, center1.y,直到等于center2.x, center2.ypath.reset();path.moveTo(point3.x, point3.y);path.quadTo(center1.x, center1.y, point4.x, point4.y);canvas.drawPath(path, paint);
//                //起始位置的圆
//                paint.setColor(Color.RED);
//                canvas.drawCircle(center1.x, center1.y, currentRadius, paint);
//                //结束位置的圆
//                paint.setColor(Color.BLUE);
//                canvas.drawCircle(center2.x, center2.y, currentRadius, paint);//原始图片canvas.drawBitmap(bitmap, center2.x - initRadius, center2.y - initRadius, paint);break;}
//        Log.d("zhen", "dragStatus: " + mDragStatus + " 圆1:" + center1 + " 圆2:" + center2 + " 半径: " + currentRadius);
//        Log.w("zhen", "dragStatus: " + mDragStatus + " point3:" + point3 + " point4" + point4 + " sinValue " + sinValue + " cosValue " + cosValue);Log.w("zhen", "dragStatus: " + mDragStatus + " 圆1:" + center1 + " 圆2:" + center2 + " 半径: " + currentRadius);}int i = 0;private boolean inAnimation = false;private void doAnimation(int dragStatus, final PointF startPoint, final PointF endPoint) {if (inAnimation) return;inAnimation = true;final int step = 10;final float stepx = (endPoint.x - startPoint.x) / step;final float stepy = (endPoint.y - startPoint.y) / step;i = 1;mDragStatus = dragStatus;Log.d("zhen", "dragStatus: " + mDragStatus + " startPoint:" + startPoint+ " endPoint:" + endPoint + " stepx: " + stepy + " stepx: " + stepy);new Thread(new Runnable() {@Overridepublic void run() {while (i <= step) {startPoint.x += stepx;startPoint.y += stepy;postInvalidate();i++;try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}mDragStatus = DragStatus.NORMAL;invalidate();Log.e("zhen", "恢复为可拖动状态");}}).start();}@IntDef({DragStatus.DRAG_MOVE, DragStatus.DRAG_TO, DragStatus.DRAG_BACK})public @interface DragStatus {int NORMAL = 0;//拖动中int DRAG_MOVE = 1;//int DRAG_TO = 2;//回弹int DRAG_BACK = 3;}}

Android自定义View——qq消息气泡相关推荐

  1. android 自定义特效,Android自定义View之高仿QQ健康

    我们都知道自定义View一般有三种直接继承View.继承原有的控件对控件的进行修改.重新拼装组合,最后一种主要针对于ViewGroup.具体的怎么做不是本文的所涉及的内容(本文是基于第一种方式实现的) ...

  2. android的动态tab,Android自定义view仿QQ的Tab按钮动画效果(示例代码)

    话不多说 先上效果图 实现其实很简单,先用两张图 一张是背景的图,一张是笑脸的图片,笑脸的图片是白色,可能看不出来.实现思路:主要是再触摸view的时候同时移动这两个图片,但是移动的距离不一样,造成的 ...

  3. android中仿qq最新版抽屉,Android 自定义View实现抽屉效果

    Android 自定义View实现抽屉效果 说明 这个自定义View,没有处理好多点触摸问题 View跟着手指移动,没有采用传统的scrollBy方法,而是通过不停地重新布局子View的方式,来使得子 ...

  4. oracle number型步数,Android自定义View仿QQ计步器

    自定义计步器 Android自定义View是Android开发中比较重要的一项,也是很多开发者比较怕的一个东西.其实只要认真去学习,自定义View其实没有那么可怕:相反的,我们还能从自定义View中找 ...

  5. 仿QQ消息气泡拖拽效果

    此次的自定义View是仿qq消息列表,消息气泡拖拽效果. 1.原理介绍:自定义view,绘制原始点圆,touch点圆,然后将两圆用贝塞尔曲线连接并填充. 2.应用WindowManager,将自定义v ...

  6. SeniorUI09_贝塞尔曲线运用(QQ消息气泡)

    高级UI汇总​​​​​​​ 源码:SeniorUI09_BezierActivity 1 效果图 2 贝塞尔曲线简介 以简单的二阶贝塞尔曲线为例 在平面内任选 3 个不共线的点,依次用线段连接. 在第 ...

  7. android自定义view获取控件,android 自定义控件View在Activity中使用findByViewId得到结果为null...

    转载:http://blog.csdn.net/xiabing082/article/details/48781489 1.  大家常常自定义view,,然后在xml 中添加该view 组件..如果在 ...

  8. android 自定义图形,Android自定义View之图形图像(模仿360的刷新球自定

    概述: 360安全卫士的那个刷新球(姑且叫它刷新球,因为真的不知道叫什么好,不是dota里的刷新球!!),里面像住了水一样,生动可爱,看似简单,写起来不太简单,本例程只是实现了它的部分功能而已,说实话 ...

  9. 精通Android自定义View(十三)事件分发简述

    1 事件序列 (1)手指接触屏幕后会产生一系列事件,事件分为3种:ACTION_DOWN(手指刚刚接触屏幕).ACTION_MOVE(手指在屏幕移动).ACTION_UP(手指从屏幕松开) (2)一个 ...

最新文章

  1. boost::phoenix::arg_names::arg1用法的测试程序
  2. 2016.9.24 の 測試
  3. 工作377-处理url拼接里面的参数方法
  4. linux 文件怎么不让删,请问如何设置权限,可以禁止用户删除文件
  5. FileZilla传输文件乱码的解决方案
  6. 化工机械基础期末复习题及答案
  7. (以三星S8为例)安卓全面屏手势设置教程
  8. 爬虫出现UnicodeEncodeError: ‘latin-1‘ codec can‘t encode character *** in position 8328: Body***问题
  9. 通过私有化部署自建一套视频流媒体服务器平台,如何解决视频播放延时卡顿问题?
  10. 数据库系统 第一部分 背景
  11. 生僻字怎么用计算机打出来,电脑搜狗输入法生僻字怎么打?电脑搜狗输入法怎么打不认识的字?...
  12. 模糊数学(Fuzzy mathematics)及其应用
  13. sap 个模块 含义 FI/CO/MM/PP/QM/WM 及其它 分别指什么模块?是干什么用的?
  14. java系统学习_java全面系统学习路线(转载)
  15. java如何连接Sublime_第一节:使用Sublime 搭建Java学习环境
  16. asp毕业设计——基于asp+access的网页设计辅导系统设计与实现(毕业论文+程序源码)——网页设计辅导系统
  17. 【工业级3D视觉技术圈-欢迎加入】
  18. Nand Flash学习笔记3-Read Disturb
  19. 【人脸检测】MTCNN网络解析
  20. c#窗体应用计算机设计,C#实验报告:Windows窗体设计.doc

热门文章

  1. 计算机教师专业技术报告,教师信息技术实习报告
  2. 疯壳-MTK智能电话手表开发串码下载
  3. Predicate Information
  4. 新品评测:2021年iPad Pro与2020年、2018年iPad Pro对比
  5. MANSCAPED™与悉尼雄鸡队延长合作关系,作为其官方腰部以下护理合作伙伴共同开启第二个赛季
  6. AOV网--拓扑排序(必须是一个有向无环图)
  7. JAVA调用小票打印机
  8. 手机经常发热怎么回事?减少这些操作,手机温度轻松降下来
  9. 在硅谷大厂实现年薪70万美元,我只用了5年
  10. 【刷题笔记】另类加法+走方格的方案数