Android自定義View實(shí)現(xiàn)QQ消息氣泡
本文實(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)過(guò)程中 ? ? ? ? ? ? ? ? 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; ? ? } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android自定義View實(shí)現(xiàn)跟隨手指移動(dòng)
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)跟隨手指移動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08Android App中使用LinearLayout進(jìn)行居中布局的實(shí)例講解
這篇文章主要介紹了Android App中使用LinearLayout進(jìn)行居中布局的實(shí)例講解,文中分別介紹了水平居中和垂直居中的相關(guān)線性布局,需要的朋友可以參考下2016-04-04Android ListView與getView調(diào)用卡頓問(wèn)題解決辦法
這篇文章主要介紹了Android ListView與getView調(diào)用卡頓問(wèn)題解決辦法的相關(guān)資料,這里提供實(shí)例及解決辦法幫助大家解決這種問(wèn)題,需要的朋友可以參考下2017-08-08android開(kāi)發(fā)教程之實(shí)現(xiàn)listview下拉刷新和上拉刷新效果
這篇文章主要介紹了android實(shí)現(xiàn)listview下拉刷新和上拉刷新效果,Android的ListView上拉下拉刷新,原理都一樣,在Touch事件中操作header/footer的paddingTop屬性,需要的朋友可以參考下2014-02-02Android基于AudioManager、PhoneStateListener實(shí)現(xiàn)設(shè)置黑名單功能
這篇文章主要介紹了Android基于AudioManager、PhoneStateListener實(shí)現(xiàn)設(shè)置黑名單功能的方法,涉及Android操作手機(jī)通信錄及通話模式與手機(jī)狀態(tài)的相關(guān)技巧,需要的朋友可以參考下2016-01-01基于Android實(shí)現(xiàn)3D翻頁(yè)效果
這篇文章主要為大家詳細(xì)介紹了基于Android實(shí)現(xiàn)3D翻頁(yè)效果的具體代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06Android實(shí)現(xiàn)EditText中添加和刪除bitmap的方法
這篇文章主要介紹了Android實(shí)現(xiàn)EditText中添加和刪除bitmap的方法,實(shí)例分析了Android中EditText控件的bitmap操作技巧,需要的朋友可以參考下2016-01-01