網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
本文實(shí)例為大家分享了Android自定義View實(shí)現(xiàn)QQ消息氣泡的具體代碼,供大家參考,具體內(nèi)容如下
效果圖:
原理:
控件源碼:
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;
? ? @DragStatus
? ? private 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);
? ? }
? ? @Override
? ? protected 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;
? ? @Override
? ? public 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", "選中狀態(tài)");
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case MotionEvent.ACTION_MOVE:
? ? ? ? ? ? ? ? if (isSelected) {
// ? ? ? ? ? ? ? ? ? ?Log.d("zhen", "拖動(dòng)距離: " + 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.y
? ? ? ? ? ? ? ? ? ? ? ? doAnimation(DragStatus.DRAG_BACK, center2, center1);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? isSelected = false;
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? return true;
? ? }
? ? @Override
? ? protected void onDraw(Canvas canvas) {
? ? ? ? super.onDraw(canvas);
? ? ? ? //圓的半徑改變
? ? ? ? currentRadius = initRadius * (1 + (minRadiusScale - 1) / defaultZoomSize * realZoomSize);
? ? ? ? if (realZoomSize > defaultZoomSize) {
? ? ? ? ? ? //圓縮小為一半,去往目的地,就應(yīng)該消失了
? ? ? ? ? ? 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:
? ? ? ? ? ? ? ? //拖動(dòng)過程中
? ? ? ? ? ? ? ? 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);
? ? ? ? ? ? ? ? //結(jié)束位置的圓
// ? ? ? ? ? ? ? ?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.y
? ? ? ? ? ? ? ? path.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.y
? ? ? ? ? ? ? ? path.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);
// ? ? ? ? ? ? ? ?//結(jié)束位置的圓
// ? ? ? ? ? ? ? ?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() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public 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", "恢復(fù)為可拖動(dòng)狀態(tài)");
? ? ? ? ? ? }
? ? ? ? }).start();
? ? }
? ? @IntDef({DragStatus.DRAG_MOVE, DragStatus.DRAG_TO, DragStatus.DRAG_BACK})
? ? public @interface DragStatus {
? ? ? ? int NORMAL = 0;
? ? ? ? //拖動(dòng)中
? ? ? ? int DRAG_MOVE = 1;
? ? ? ? //
? ? ? ? int DRAG_TO = 2;
? ? ? ? //回彈
? ? ? ? int DRAG_BACK = 3;
? ? }
}
原文鏈接:https://blog.csdn.net/ZHENZHEN9310/article/details/94180208
相關(guān)推薦
- 2022-06-19 dockerfile指令構(gòu)建docker鏡像的示例代碼_docker
- 2023-05-06 Python格式化輸出的幾種匯總_python
- 2023-01-20 python使用paramiko執(zhí)行服務(wù)器腳本并拿到實(shí)時(shí)結(jié)果_python
- 2022-04-02 vscode?采用C++17版本進(jìn)行編譯的實(shí)現(xiàn)_C 語(yǔ)言
- 2022-10-16 Ant?Design?組件庫(kù)按鈕實(shí)現(xiàn)示例詳解_React
- 2022-07-14 一文教會(huì)你用redux實(shí)現(xiàn)computed計(jì)算屬性_React
- 2022-09-17 python?df遍歷的N種方式(小結(jié))_python
- 2023-11-19 如何卸載k3s?
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支