Android imitation QQ message drag and drop adhesion disappearing effect, bubble explosion effect

The company needs this effect, read a lot of blogs, and wrote a complete process according to the needs of its own projects. 

 

 

 Drag control code

Use the Bezier curve algorithm to draw the control according to the position of the gesture drag


package cn.stike.bubble.stickbubbledemo.view;

import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.WindowManager;


public class StickBubble extends LLBBubble {

    private LRBubble mInnerStickBall;
    // 手抬起时的回调
    private OnDragUpListener mOnDragUpListener;
    private WindowManager mWindowManager;
    private float getCurrentX;
    private float getCurrentY;

    public float getGetCurrentX() {
        return getCurrentX;
    }

    public void setGetCurrentX(float getCurrentX) {
        this.getCurrentX = getCurrentX;
    }

    public float getGetCurrentY() {
        return getCurrentY;
    }

    public void setGetCurrentY(float getCurrentY) {
        this.getCurrentY = getCurrentY;
    }

    public StickBubble(Context context) {
        this(context, null);
    }

    public StickBubble(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public StickBubble(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mLTPoint.set(getPaddingLeft() + mContentHeight / 2, getPaddingTop());
        mRBPoint.set(mLTPoint.x + mContentWidth - mContentHeight, mLTPoint.y + mContentHeight);
        mBaseLinePoint.set(getPaddingLeft() + (mContentWidth - mBounds.width()) / 2, getPaddingTop() + (mContentHeight + mBounds.height()) / 2);
        widthMeasureSpec = MeasureSpec.makeMeasureSpec(mContentWidth + getPaddingLeft() + getPaddingRight(), MeasureSpec.getMode(widthMeasureSpec));
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(mContentHeight + getPaddingTop() + getPaddingBottom(), MeasureSpec.getMode(heightMeasureSpec));
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (mHasDown) {
                    return true;
                }
                mHasDown = true;
                setVisibility(INVISIBLE);
                showDragView();
                return true;
            case MotionEvent.ACTION_MOVE:
                mInnerStickBall.performTouchEvent(event);
                return true;
            case MotionEvent.ACTION_UP:
                /**
                 *记录bubble气泡爆炸应出现的坐标值
                 */
                setGetCurrentX(event.getRawX());
                setGetCurrentY(event.getRawY());
                mInnerStickBall.performTouchEvent(event);
                return true;
        }
        return super.onTouchEvent(event);
    }
    int[] outSize;
    private void showDragView() {
        outSize = new int[2];
        getLocationOnScreen(outSize);
        mInnerStickBall = new LRBubble(getContext(),
                new PointF(mLTPoint.x + outSize[0], mLTPoint.y + outSize[1]),
                new PointF(mRBPoint.x + outSize[0], mRBPoint.y + outSize[1]),
                mMaxDistance, getText(), mTextColor, mBallColor, getPaint());
        mInnerStickBall.setOnDragUpListener(new OnDragUpListener() {
            @Override
            public void onDragUp(boolean overstep) {
                if (mWindowManager != null) {
                    mWindowManager.removeView(mInnerStickBall);
                }
                if (!overstep) {
                    setVisibility(VISIBLE);
                }
                if (mOnDragUpListener != null) {
                    mOnDragUpListener.onDragUp(overstep);
                }
                mHasDown = false;
            }
        });
        if (mWindowManager == null) {
            return;
        }
        WindowManager.LayoutParams params = new WindowManager.LayoutParams();
        params.format = PixelFormat.TRANSLUCENT;
        params.type |= WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
        mWindowManager.addView(mInnerStickBall, params);
    }

    /**
     * 设置判定超出范围的最大距离
     *
     * @param maxDistance
     */
    public void setMaxDistance(double maxDistance) {
        mMaxDistance = maxDistance;
    }

    public void setOnDragUpListener(OnDragUpListener onDragUpListener) {
        mOnDragUpListener = onDragUpListener;
    }

    /**
     * 手指抬起时的回调
     */
    public interface OnDragUpListener {
        /**
         * @param overstep true表示超过最大范围,粘性球消失,false表示未超过范围,粘性球未消失
         */
        void onDragUp(boolean overstep);
    }

}

Activity code

Use frame animation to show the effect of bubble explosion. Frame animation is implemented in xml. It's very simple. No code is posted here.


package cn.stike.bubble.stickbubbledemo;

import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.drawable.AnimationDrawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;

import cn.stike.bubble.stickbubbledemo.view.BubbleLayout;
import cn.stike.bubble.stickbubbledemo.view.StickBall;

public class MainActivity extends TabActivity {
    private TabHost tabHost;
    int CurrentPage;
    int setlanguage;
    TabHost.TabSpec spec;
    private StickBall mybragballview;
    private WindowManager mWm;
    private WindowManager.LayoutParams mParams;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mWm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        mParams = new WindowManager.LayoutParams();
        mParams.format = PixelFormat.TRANSLUCENT;//使窗口支持透明度

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            mParams.flags = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
        }
        mybragballview = (StickBall) findViewById(R.id.mybragballview);
        mybragballview.setOnDragUpListener(new StickBall.OnDragUpListener() {
            @Override
            public void onDragUp(boolean overstep) {
                if (overstep) {//气泡消失   在此气泡爆炸的动画开始出现
                    showDisapearBubble();
                }
            }
        });
    }


    public void showDisapearBubble() {
        if (mWm != null && mybragballview.getParent() != null) {

            //播放气泡爆炸动画
            ImageView imageView = new ImageView(MainActivity.this);
            imageView.setImageResource(R.drawable.anim_bubble_pop);
            AnimationDrawable mAnimDrawable = (AnimationDrawable) imageView
                    .getDrawable();

            final BubbleLayout bubbleLayout = new BubbleLayout(MainActivity.this);
            //获取bubble气泡爆炸出现的坐标值  显示
            int x = (int) mybragballview.getGetCurrentX();
            int y = (int) mybragballview.getGetCurrentY();
            bubbleLayout.setCenter(x, y);

            bubbleLayout.addView(imageView, new FrameLayout.LayoutParams(
                    android.widget.FrameLayout.LayoutParams.WRAP_CONTENT,
                    android.widget.FrameLayout.LayoutParams.WRAP_CONTENT));

            mWm.addView(bubbleLayout, mParams);

            mAnimDrawable.start();

            // 播放结束后,删除该bubbleLayout
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mWm.removeView(bubbleLayout);
                }
            }, 501);
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    //更新界面把所有消息变成已读
                }
            }, 510);
        }
    }
}

bubble explosion layout


package cn.stike.bubble.stickbubbledemo.view;

import android.content.Context;
import android.view.View;
import android.widget.FrameLayout;

/**
 * Created by Administrator on 2018/9/19.
 * 播放爆炸动画的layout
 */

public class BallLayout extends FrameLayout {
    Context context;

    public BallLayout(Context context) {
        super(context);
        this.context = context;
    }

    private int mCenterX, mCenterY;

    public void setCenter(int x, int y) {
        mCenterX = x;
        mCenterY = y;
        requestLayout();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
                            int bottom) {
        View child = getChildAt(0);
        // 设置View到指定位置
        if (child != null && child.getVisibility() != GONE) {
            final int width = child.getMeasuredWidth();
            final int height = child.getMeasuredHeight();
            child.layout((int) (mCenterX - width / 2.0f), (int) (mCenterY - height / 2.0f)
                    , (int) (mCenterX + width / 2.0f), (int) (mCenterY + height / 2.0f));
        }
    }
}

Demo download URL: https://download.csdn.net/download/congcongguniang/10676281

Guess you like

Origin blog.csdn.net/congcongguniang/article/details/82770845