Android CV系列 > QQ未读消息拖拽

//noinspection GradleCompatible
implementation 'com.android.support:design:26.1.0'
//RecyclerView 快速适配器
compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30

1.仔细看有口痰  CustomView

public class TipsView extends FrameLayout {

    public static final float DEFAULT_RADIUS = 20;

    private Paint paint;
    private Path path;

    float x = 0;
    float y = 0;

    /**
     * 锚点位置
     */
    float anchorX = 0;
    float anchorY = 0;

    float startX = 500;
    float startY = 100;

    /**
     * 在屏幕中的位置
     */
    float locationX = 0;
    float locationY = 0;

    float radius = DEFAULT_RADIUS;

    boolean isTrigger; //是否断开
    boolean  isTouch;  //是否正在触摸

    ImageView exploredImageView;
    View tipImageView;

    public TipsView(Context context) {
        super(context);
        initialize();
    }

    public TipsView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize();
    }

    public TipsView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initialize();
    }

    private void initialize() {
        setBackgroundColor(Color.TRANSPARENT);
        path = new Path();

        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        paint.setStrokeWidth(2);
        paint.setColor(0xffed5050);

        LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        exploredImageView = new ImageView(getContext());
        exploredImageView.setLayoutParams(params);
        exploredImageView.setImageResource(R.drawable.tips_bubble);
        exploredImageView.setVisibility(View.INVISIBLE);
        addView(exploredImageView);
    }

    public void setColor(int color){
        paint.setColor(color);
    }

    /**
     * 计算贝塞尔曲线
     */
    private void calculate() {
        float distance = (float) Math.sqrt(Math.pow(y - startY, 2) + Math.pow(x - startX, 2));
        radius = -distance / 15 + DEFAULT_RADIUS;

        if (radius < 5) {
            isTrigger = true;
        } else {
            isTrigger = false;
        }

        float offsetX = (float) (radius * Math.sin(Math.atan((y - startY) / (x - startX))));
        float offsetY = (float) (radius * Math.cos(Math.atan((y - startY) / (x - startX))));

        float x1 = startX - offsetX;
        float y1 = startY + offsetY;

        float x2 = x - offsetX;
        float y2 = y + offsetY;

        float x3 = x + offsetX;
        float y3 = y - offsetY;

        float x4 = startX + offsetX;
        float y4 = startY - offsetY;

        path.reset();
        path.moveTo(x1, y1);
        path.quadTo(anchorX, anchorY, x2, y2);
        path.lineTo(x3, y3);
        path.quadTo(anchorX, anchorY, x4, y4);
        path.lineTo(x1, y1);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        calculate();
        if (isTrigger || !isTouch || tipImageView == null) {
            canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.OVERLAY);
        } else {
            canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.OVERLAY);
            canvas.drawPath(path, paint);
            canvas.drawCircle(startX, startY, radius, paint);
            canvas.drawCircle(x, y, radius, paint);
        }
        super.onDraw(canvas);
    }

    public void attach(final View attachView) {
        attach(attachView, null);
    }

    public void attach(final View attachView, DragListener dragListener) {
        attach(attachView, new ViewCreator<View>() {
            @Override
            public View invoke() {
                Bitmap bm = view2Bitmap(attachView);
                ImageView iv = new ImageView(getContext());
                iv.setImageBitmap(bm);
                return iv;
            }
        }, dragListener);
    }

    public void attach(final View attachView, final ViewCreator<View> copyViewCreator, final DragListener dragListener) {
        bringToFront();

        attachView.setOnTouchListener(new OnTouchListener() {
            protected void init() {
                int[] attachLocation = new int[2];
                attachView.getLocationOnScreen(attachLocation);
                int[] thisLocation = new int[2];
                TipsView.this.getLocationOnScreen(thisLocation);

                startX = attachLocation[0] - thisLocation[0] + attachView.getWidth() / 2;
                startY = attachLocation[1] - thisLocation[1] + attachView.getHeight() / 2;

                x = startX;
                y = startY;

                tipImageView = copyViewCreator.invoke();

                tipImageView.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
                TipsView.this.addView(tipImageView);
                tipImageView.measure(0, 0);

                tipImageView.setX(startX - tipImageView.getMeasuredWidth() / 2);
                tipImageView.setY(startY - tipImageView.getMeasuredHeight() / 2);

                attachView.setVisibility(INVISIBLE);
                requestDisallowInterceptTouchEvent(attachView,true);

                if (dragListener != null) {
                    dragListener.onStart();
                }
            }

            protected void destory() {
                TipsView.this.removeView(tipImageView);
            }

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    init();
                    isTouch = true;
                    int[] location = new int[2];
                    TipsView.this.getLocationOnScreen(location);
                    locationX = location[0];
                    locationY = location[1];

                    invalidate();
                    return true;
                }

                if (!isTouch)
                    return false;

                if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
                    isTouch = false;
                    destory();

                    requestDisallowInterceptTouchEvent(attachView,false);

                    if (isTrigger) {
                        postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                isTrigger = false;
                                if (dragListener != null) {
                                    dragListener.onComplete();
                                }
                            }
                        }, 1000);

                        /**
                         * 在释放位置显示消除动画
                         */
                        exploredImageView.setX(x - exploredImageView.getWidth() / 2);
                        exploredImageView.setY(y - exploredImageView.getHeight() / 2);
                        exploredImageView.setVisibility(View.VISIBLE);
                        ((AnimationDrawable) exploredImageView.getDrawable()).stop();
                        ((AnimationDrawable) exploredImageView.getDrawable()).start();

                    } else {
                        attachView.setVisibility(VISIBLE);
                        if (dragListener != null) {
                            dragListener.onCancel();
                        }
                    }
                }

                anchorX = (event.getRawX() - locationX + startX) / 2;
                anchorY = (event.getRawY() - locationY + startY) / 2;
                x = event.getRawX() - locationX;
                y = event.getRawY() - locationY;

                tipImageView.setX(x - tipImageView.getWidth() / 2);
                tipImageView.setY(y - tipImageView.getHeight() / 2);

                invalidate();
                return true;
            }
        });
    }

    /**
     * 用于拦截其 parent 的touch事件
     * @param view
     */
    protected void requestDisallowInterceptTouchEvent(View view,boolean isDisallow){
        if(view.getParent() instanceof ViewGroup) {
            ViewGroup parent = (ViewGroup)view.getParent();
            parent.requestDisallowInterceptTouchEvent(isDisallow);
        }
    }

    /**
     * View 转 bitmap
     * @param v
     * @return
     */
    public static Bitmap view2Bitmap(final View v) {
        Bitmap bm = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bm);
        v.draw(canvas);
        return bm;
    }

    public interface ViewCreator<Tresult> {
        Tresult invoke();
    }

    /**
     * 拖动监听接口
     */
    public interface DragListener {
        void onStart();

        void onComplete();

        void onCancel();
    }

    /**
     * 用于页面复用管理
     */
    private static WeakReference<TipsView> instance;
    public static TipsView create(final Activity activity) {
        if(instance!=null && instance.get()!=null && instance.get().getTag() == activity){
            return instance.get();
        }
        instance = new WeakReference<>(new TipsView(activity));
        instance.get().setTag(activity);
        ViewGroup.LayoutParams vlp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        activity.addContentView(instance.get(),vlp) ;
        return instance.get();
    }
}

2.Adapter

public class MyAdapter extends BaseQuickAdapter<String,BaseViewHolder> {

    private Activity activity;

    public void setActivity(Activity activity) {
        this.activity = activity;
    }

    public MyAdapter(int layoutResId, @Nullable List<String> data) {
        super(layoutResId, data);
    }

    @Override
    protected void convert(BaseViewHolder helper, String item) {
        ImageView image = helper.getView(R.id.image_item);
        TipsView.create(activity)
                .attach(image, new TipsView.DragListener() {
                    @Override
                    public void onStart() {
                        Toast.makeText(activity, "onStart", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onComplete() {
                        Toast.makeText(activity, "onComplete", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onCancel() {
                        Toast.makeText(activity, "onCancel", Toast.LENGTH_SHORT).show();
                    }
                });
    }
}

3.MainAc

  private RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            list.add("" + i);
        }
        MyAdapter myAdapter = new MyAdapter(R.layout.item, list);
        myAdapter.setActivity(this);
        recyclerView.setAdapter(myAdapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
    }

    private void initView() {
        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
    }

4.MainXML

  <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

5.item

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/tvLeft"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:text="我就是数据" />

    <ImageView
        android:id="@+id/image_item"
        android:layout_width="20dp"
        android:layout_height="10dp"
        android:layout_alignParentRight="true"
        android:layout_marginRight="20dp"
        android:src="@drawable/oval" />
</RelativeLayout>

6.oval.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval" >

    <solid android:color="#f00" />

    <corners android:radius="5dip" />

7.tips_bubble.xml

<?xml version="1.0" encoding="utf-8"?>
<animation-list
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item android:drawable="@drawable/tips_bubble_idp" android:duration="300"/>
    <item android:drawable="@drawable/tips_bubble_idq" android:duration="300"/>
    <item android:drawable="@drawable/tips_bubble_idr" android:duration="300"/>
    <item android:drawable="@drawable/tips_bubble_ids" android:duration="300"/>
    <item android:drawable="@drawable/tips_bubble_idt" android:duration="300"/>
    <item android:drawable="@android:color/transparent" android:duration="300"/>
</animation-list>

8.https://github.com/Qiaoidea/QQTipsView 下载5张图

猜你喜欢

转载自blog.csdn.net/FlyPig_Vip/article/details/81909985