Android仿QQ消息拖拽黏连消失效果,气泡爆炸效果

公司需要这个效果,看了很多博客,根据自己项目的需要写出来的一个完整的过程. 

 拖拽控件代码

根据手势拖动的位置利用贝塞尔曲线算法画出控件


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代码

使用帧动画将气泡爆炸的效果展现出来,帧动画是用xml实现的,很简单,这里就不贴代码了


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爆炸布局


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下载网址:https://download.csdn.net/download/congcongguniang/10676281

猜你喜欢

转载自blog.csdn.net/congcongguniang/article/details/82770845
今日推荐