仿QQ未读数清除效果 & 融云未读数监听与清除

本篇给大家讲述如何实现QQ未读数清除效果 和 融云未读数监听与清除

此文为笔者原创,转载请标明出处: http://blog.csdn.net/qq_19986309 请尊重他人劳动成果。

话不多说先看效果:

clearunread

是不是效果相当酷炫 ~ /偷笑 不过先声明 这个 TextView
的自定义控件不是笔者写的, 不过也不得不佩服这位老兄自定义控件的功夫,代码中也没找到这位老兄的联系方式.在此默默的先谢过了

代码:


public class DragPointView extends TextView {
    private boolean initBgFlag;
    private OnDragListencer dragListencer;
    private int backgroundColor = Color.RED;
    private PointView pointView;
    private int x, y, r;
    private ViewGroup scrollParent;
    private int[] p = new int[2];

    public DragPointView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initbg();
    }

    public OnDragListencer getDragListencer() {
        return dragListencer;
    }

    public void setDragListencer(OnDragListencer dragListencer) {
        this.dragListencer = dragListencer;
    }

    public int getBackgroundColor() {
        return backgroundColor;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
        int w = getMeasuredWidth();
        int h = getMeasuredHeight();
        if(w != h){ // 简单的将宽高搞成一样的,如果有更好的方法欢迎在我博客下方留言!
            int x = Math.max(w, h);
            setMeasuredDimension(x, x);
        }
    }

    @SuppressWarnings("deprecation")
    public void setBackgroundColor(int backgroundColor) {
        this.backgroundColor = backgroundColor;
        DragPointView.this.setBackgroundDrawable(createStateListDrawable((getHeight() > getWidth() ? getHeight()
                : getWidth()) / 2, backgroundColor));
    }

    private void initbg() {
        setGravity(Gravity.CENTER);
        getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {

            @SuppressWarnings("deprecation")
            @Override
            public boolean onPreDraw() {
                if (!initBgFlag) {
                    DragPointView.this.setBackgroundDrawable(createStateListDrawable(
                            (getHeight() > getWidth() ? getHeight() : getWidth()) / 2, backgroundColor));
                    initBgFlag = true;
                    return false;
                }
                return true;
            }
        });
    }


    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        View root = getRootView();
        if (root == null || !(root instanceof ViewGroup)) {
            return false;
        }
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            root.getLocationOnScreen(p);
            scrollParent = getScrollParent();
            if (scrollParent != null) {
                scrollParent.requestDisallowInterceptTouchEvent(true);
            }
            int location[] = new int[2];
            getLocationOnScreen(location);
            x = location[0] + (getWidth() / 2) - p[0];
            y = location[1] + (getHeight() / 2) - p[1];
            r = (getWidth() + getHeight()) / 4;
            pointView = new PointView(getContext());
            pointView.setLayoutParams(new ViewGroup.LayoutParams(root.getWidth(), root.getHeight()));
            setDrawingCacheEnabled(true);
            pointView.catchBitmap = getDrawingCache();
            pointView.setLocation(x, y, r, event.getRawX() - p[0], event.getRawY() - p[1]);
            ((ViewGroup) root).addView(pointView);
            setVisibility(View.INVISIBLE);
            break;
        case MotionEvent.ACTION_MOVE:
            pointView.refrashXY(event.getRawX() - p[0], event.getRawY() - p[1]);
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            if (scrollParent != null) {
                scrollParent.requestDisallowInterceptTouchEvent(false);
            }
            if (!pointView.broken) { // 没有拉断
                pointView.cancel();
            } else if (pointView.nearby) {// 拉断了,但是又回去了
                pointView.cancel();
            } else { // 彻底拉断了
                pointView.broken();
            }
            break;
        default:
            break;
        }
        return true;
    }

    private ViewGroup getScrollParent() {
        View p = this;
        while (true) {
            View v;
            try {
                v = (View) p.getParent();
            } catch (ClassCastException e) {
                return null;
            }
            if (v == null)
                return null;
            if (v instanceof AbsListView || v instanceof ScrollView || v instanceof ViewPager) {
                return (ViewGroup) v;
            }
            p = v;
        }
    }

    public interface OnDragListencer {
        public void onDragOut();
    }

    class PointView extends View {
        private Bitmap catchBitmap;
        private Circle c1;
        private Circle c2;
        private Paint paint;
        private Path path = new Path();
        private int maxDistance = 10; // 10倍半径距离视为拉断
        private boolean broken; // 是否拉断过
        private boolean out; // 放手的时候是否拉断
        private boolean nearby;
        private int brokenProgress;

        public PointView(Context context) {
            super(context);
            init();
        }

        public void init() {
            paint = new Paint();
            paint.setColor(backgroundColor);
            paint.setAntiAlias(true);
        }

        public void setLocation(float c1X, float c1Y, float r, float endX, float endY) {
            broken = false;
            c1 = new Circle(c1X, c1Y, r);
            c2 = new Circle(endX, endY, r);
        }

        public void refrashXY(float x, float y) {
            c2.x = x;
            c2.y = y;
            // 以前的半径应该根据距离缩小点了
            // 计算出距离
            double distance = c1.getDistance(c2);
            int rate = 10;
            c1.r = (float) ((c2.r * c2.r * rate) / (distance + (c2.r * rate)));
            Log.i("info", "c1: " + c1.r);
            invalidate();
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawColor(Color.TRANSPARENT);
            if (out) {
                float dr = c2.r / 2 + c2.r * 4 * (brokenProgress / 100f);
                Log.i("info", "dr" + dr);
                canvas.drawCircle(c2.x, c2.y, c2.r / (brokenProgress + 1), paint);
                canvas.drawCircle(c2.x - dr, c2.y - dr, c2.r / (brokenProgress + 2), paint);
                canvas.drawCircle(c2.x + dr, c2.y - dr, c2.r / (brokenProgress + 2), paint);
                canvas.drawCircle(c2.x - dr, c2.y + dr, c2.r / (brokenProgress + 2), paint);
                canvas.drawCircle(c2.x + dr, c2.y + dr, c2.r / (brokenProgress + 2), paint);
            } else {
                // 绘制手指跟踪的圆形
                canvas.drawBitmap(catchBitmap, c2.x - c2.r, c2.y - c2.r, paint);
                path.reset();
                float deltaX = c2.x - c1.x;
                float deltaY = -(c2.y - c1.y);
                double distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
                double sin = deltaY / distance;
                double cos = deltaX / distance;
                nearby = distance < c2.r * maxDistance;
                if (nearby && !broken) {
                    canvas.drawCircle(c1.x, c1.y, c1.r, paint);
                    path.moveTo((float) (c1.x - c1.r * sin), (float) (c1.y - c1.r * cos));
                    path.lineTo((float) (c1.x + c1.r * sin), (float) (c1.y + c1.r * cos));
                    path.quadTo((c1.x + c2.x) / 2, (c1.y + c2.y) / 2, (float) (c2.x + c2.r * sin), (float) (c2.y + c2.r
                            * cos));
                    path.lineTo((float) (c2.x - c2.r * sin), (float) (c2.y - c2.r * cos));
                    path.quadTo((c1.x + c2.x) / 2, (c1.y + c2.y) / 2, (float) (c1.x - c1.r * sin), (float) (c1.y - c1.r
                            * cos));
                    canvas.drawPath(path, paint);
                } else {
                    broken = true; // 已经拉断了
                }
            }

        }

        public void cancel() {
            int duration = 150;
            AnimatorSet set = new AnimatorSet();
            ValueAnimator animx = ValueAnimator.ofFloat(c2.x, c1.x);
            animx.setDuration(duration);
            animx.setInterpolator(new OvershootInterpolator(2));
            animx.addUpdateListener(new AnimatorUpdateListener() {

                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    c2.x = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            ValueAnimator animy = ValueAnimator.ofFloat(c2.y, c1.y);
            animy.setDuration(duration);
            animy.setInterpolator(new OvershootInterpolator(2));
            animy.addUpdateListener(new AnimatorUpdateListener() {

                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    c2.y = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            set.playTogether(animx, animy);
            set.addListener(new AnimatorListenerAdapter() {

                @Override
                public void onAnimationEnd(Animator animation) {
                    ViewGroup vg = (ViewGroup) PointView.this.getParent();
                    vg.removeView(PointView.this);
                    DragPointView.this.setVisibility(View.VISIBLE);
                }
            });
            set.start();

        }

        public void broken() {
            out = true;
            int duration = 500;
            ValueAnimator a = ValueAnimator.ofInt(0, 100);
            a.setDuration(duration);
            a.setInterpolator(new LinearInterpolator());
            a.addUpdateListener(new AnimatorUpdateListener() {

                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    brokenProgress = (int) animation.getAnimatedValue();
                    invalidate();
                }
            });
            a.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    ViewGroup vg = (ViewGroup) PointView.this.getParent();
                    vg.removeView(PointView.this);
                }
            });
            a.start();
            if (dragListencer != null) {
                dragListencer.onDragOut();
            }
        }

        class Circle {
            float x;
            float y;
            float r;

            public Circle(float x, float y, float r) {
                this.x = x;
                this.y = y;
                this.r = r;
            }

            public double getDistance(Circle c) {
                float deltaX = x - c.x;
                float deltaY = y - c.y;
                double distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
                return distance;
            }
        }

    }

    /**
     * 
     * @param radius
     *            圆角角度
     * @param color
     *            填充颜色
     * @return StateListDrawable 对象
     * @author zy
     */
    public static StateListDrawable createStateListDrawable(int radius, int color) {
        StateListDrawable bg = new StateListDrawable();
        GradientDrawable gradientStateNormal = new GradientDrawable();
        gradientStateNormal.setColor(color);
        gradientStateNormal.setShape(GradientDrawable.RECTANGLE);
        gradientStateNormal.setCornerRadius(radius);
        gradientStateNormal.setStroke(0, 0);
        bg.addState(View.EMPTY_STATE_SET, gradientStateNormal);
        return bg;
    }

}

上面的代码 copy 过去就能拿去用 希望还能更加优化的朋友再 blog 下方留言分享 再说说 DragPointView 使用方式 和 融云未读消息总数监听与状态清除:


private void initUnreadCountListener() {
        final Conversation.ConversationType[] conversationTypes = {Conversation.ConversationType.PRIVATE, Conversation.ConversationType.DISCUSSION,
                Conversation.ConversationType.GROUP, Conversation.ConversationType.SYSTEM,
                Conversation.ConversationType.PUBLIC_SERVICE};

        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                RongIM.getInstance().setOnReceiveUnreadCountChangedListener(mCountListener, conversationTypes);
            }
        }, 500);
    }


public RongIM.OnReceiveUnreadCountChangedListener mCountListener = new RongIM.OnReceiveUnreadCountChangedListener() {
    @Override
    public void onMessageIncreased(int count) {
        Log.e("MainActivity", "count:" + count);
        if (count == 0) {
            mUnreadCount.setVisibility(View.GONE);
        } else if (count > 0 && count < 100) {
            mUnreadCount.setVisibility(View.VISIBLE);
            mUnreadCount.setText(count + "");
        } else {
            mUnreadCount.setVisibility(View.VISIBLE);
            mUnreadCount.setText("···");
        }
    }
};


 @Override
    public void onDragOut() {
        if (RongIM.getInstance() != null) {
            List<Conversation> conversationList = RongIM.getInstance().getRongIMClient().getConversationList();
            if (conversationList != null && conversationList.size() > 0) {
                for (Conversation c : conversationList) {
                    RongIM.getInstance().getRongIMClient().clearMessagesUnreadStatus(c.getConversationType(), c.getTargetId());
                }
                mUnreadCount.setVisibility(View.GONE);
                }
        }
    }
第一段代码是设置融云未读数的监听,需要注意的是 这个监听建议设置在生命周期较长的组件 第二点 需要注意的是 设置的参数不要自己去画蛇添足的添加 聊天室 和 客服的会话类型 这两个会话类型是不计入未读数的 此处还可以参考 融云官网Demo的编写方式,此处感谢@bob.
第三段代码即使对自定义控件的使用 拖拽以后气泡消失的监听 里面的代码获取当前的会话列表的集合.然后我遍历这个集合,然后清除未读数 通过上面的 gif 我们看到效果还是不错的~!
顺便给自己打个小广告 /尴尬 欢迎 star https://github.com/13120241790/SeaStar

此文为笔者原创,转载请标明出处: http://blog.csdn.net/qq_19986309 请尊重他人劳动成果。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值