Android 高仿微信朋友评论列表与点击事件

前言

距离上一次发布文章又沉静了一段时间了,想到要写什么又感觉有点简单了,拖着拖着又不想写了。最近需求有个类似微信朋友圈的评论列表功能,

所以就静下心来写一下,写段代码,大神勿喷,可能有可能地方存在漏洞,看出问题的哥们也可以留言指出我的问题,大家共同进步。

正文:
那么接下来先看一下效果,看看是不是你想要的效果,(当然如果是鄙人的话,看到效果不是自己想要的或者说不是类似的我就会懒得看了)
当然这个做的还有很多需要优化的地方,有很多可以改进的地方。大家做为参考学习使用。

直接上图


效果呢就是这么一个效果,low 呢是有那么一点low。

不过这个不重要,这都是文本颜色字体的问题,调一调就好了


Demo地址:https://download.csdn.net/download/qq_35070105/10352996


好那么接下来就给大家先整理出来了怎么去使用

(简单用的才爽)

先说一下设置值显示的方法这里就简单的看一下 两个方法(下面会给完整的代码的)

/**
     * 设置显示数据
     *
     * @param commentator 回复人
     * @param content 回复内容
     */
    public void setTextContent(String commentator,String content){
        setTextContent(commentator,null ,content);
    }

    /**
     * 设置显示数据
     *
     * @param commentator 回复人
     * @param criticised 被回复人
     * @param content 回复内容
     */
    public void setTextContent(String commentator,String criticised,String content){
        SpannableStringBuilder ssb = new SpannableStringBuilder();
        setMovementMethod(LinkTouchMovementMethod.getInstance());
        if (commentator != null){
            ssb.append(commentator);
            ssb.setSpan(new TouchableSpan(REPLY),0,commentator.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        if (criticised != null){
            ssb.append(REPLY_HINT);
            ssb.append(criticised);
            ssb.setSpan(new TouchableSpan(REPLY_TO),
                        commentator.length()+REPLY_HINT.length(),
                        commentator.length()+REPLY_HINT.length()+criticised.length(),
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        if (content != null){
            ssb.append(":"+content);
        }
        this.setText(ssb,BufferType.NORMAL);
    }


好了设置数据参数的就只有这两个方法了。那么接下来我再介绍一下,这个自定义的View中有什么属性可以使用呢!先给大家看一下用法。

<com.example.peng.butterknifetest.UICommentTextView
        android:id="@+id/ui_comment_text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="#333333"
        android:textSize="24sp"
        app:comment_IsLongClickCopyOf="true"
        app:comment_UserHintColor="#ff0000"
        app:comment_UserHintBgNormalColor="@android:color/transparent"
        app:comment_UserHintBgPressedColor="#e0e0e0"
        app:comment_ViewBackgroundNormalColor="@android:color/transparent"
        app:comment_ViewBackgroundPressedColor="#e0e0e0"/>

那么我在这就介绍一下这个熟悉分别代表的是什么意思



效果如果都设置好了,样式也调式到美美的状态,那么下面应该是做点,点击事件了
(我们在Xml 布局文件写完,在java 文件中找到控件,
findViewbyId 还是使用 ButterKnife 这个就根据你自己喜欢咯)
这里就三个方法,可以根据你自己需要重写


uiCommentTextView.setCommentTextViewListener(new CommentTextViewListener(){
            @Override
            public void OnLongClick(Context context, UICommentTextView textView) {
                Toast.makeText(MainActivity.this,"OnLongClick",Toast.LENGTH_SHORT).show();
            }

            @Override
            public void OnReplyClick(Context context) {
                Toast.makeText(MainActivity.this,"OnReplyClick",Toast.LENGTH_SHORT).show();
            }

            @Override
            public void OnReplyToClick(Context context) {
                Toast.makeText(MainActivity.this,"OnReplyToClick",Toast.LENGTH_SHORT).show();
            }
        });

那么接下来我就直接贴代码了(不在做过多的介绍咯)


/**
 * Created by Peng on 2018/1/13.
 */
@SuppressLint("AppCompatCustomView")
public class UICommentTextView extends TextView {

    private final static int REPLY = 0x1;
    private final static int REPLY_TO = 0x2;

    private static boolean mIsInteriorClick = false;//内部是否被点击
    private static boolean mIsLongClick = false;//是否是长按

    private static final int COMMENTATOR_USER_HINT_COLOR = 0xFF0000FF;
    private static final int COMMENTATOR_HINT_BG_PRESSED = 0xFFE0E0E0;
    private static final int COMMENTATOR_HINT_BG_NORMAL = 0x00000000;
    private static final int UI_BACKGROUND_RESOURCE_PRESSED_COLOR = 0xFFE0E0E0;
    private static final int UI_BACKGROUND_RESOURCE_NORMAL_COLOR = 0x00000000;

    private static int mUserHintColor = COMMENTATOR_USER_HINT_COLOR;
    private static int mUserHintBgPressedColor = COMMENTATOR_HINT_BG_PRESSED;
    private static int mUserHintBgNormalColor = COMMENTATOR_HINT_BG_NORMAL;
    private static int mViewBackgroundPressedColor = UI_BACKGROUND_RESOURCE_PRESSED_COLOR;
    private static int mViewBackgroundNormalColor = UI_BACKGROUND_RESOURCE_NORMAL_COLOR;
    private static boolean mIsLongClickCopyOf = false;

    private String REPLY_HINT = "回复";

    private CommentTextViewListener commentTextViewListener;

    public UICommentTextView(Context context) {
        super(context);
    }

    public UICommentTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initAttr(context,attrs);
    }

    public UICommentTextView(final Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttr(context,attrs);
    }


    private void initAttr(Context context, AttributeSet attrs) {
        if (attrs == null) return;
        TypedArray type = getContext().obtainStyledAttributes(attrs, R.styleable.UICommentTextView);
        if (type == null) return;
        for (int i = 0; i < type.getIndexCount(); i++) {
            int attr = type.getIndex(i);
            if (attr == R.styleable.UICommentTextView_comment_UserHintColor){
                mUserHintColor = type.getInteger(attr,COMMENTATOR_USER_HINT_COLOR);
            }else if (attr == R.styleable.UICommentTextView_comment_UserHintBgPressedColor){
                mUserHintBgPressedColor = type.getInteger(attr,COMMENTATOR_HINT_BG_PRESSED);
            }else if (attr == R.styleable.UICommentTextView_comment_UserHintBgNormalColor){
                mUserHintBgNormalColor = type.getInteger(attr,COMMENTATOR_HINT_BG_NORMAL);
            }else if (attr == R.styleable.UICommentTextView_comment_ViewBackgroundPressedColor){
                mViewBackgroundPressedColor = type.getInteger(attr,UI_BACKGROUND_RESOURCE_PRESSED_COLOR);
            }else if (attr == R.styleable.UICommentTextView_comment_ViewBackgroundNormalColor){
                mViewBackgroundNormalColor = type.getInteger(attr,UI_BACKGROUND_RESOURCE_NORMAL_COLOR);
            }else if (attr == R.styleable.UICommentTextView_comment_IsLongClickCopyOf){
                mIsLongClickCopyOf = type.getBoolean(attr,false);
            }
        }
        type.recycle();
    }

    /**
     * 设置显示数据
     *
     * @param commentator 回复人
     * @param content 回复内容
     */
    public void setTextContent(String commentator,String content){
        setTextContent(commentator,null ,content);
    }

    /**
     * 设置显示数据
     *
     * @param commentator 回复人
     * @param criticised 被回复人
     * @param content 回复内容
     */
    public void setTextContent(String commentator,String criticised,String content){
        SpannableStringBuilder ssb = new SpannableStringBuilder();
        setMovementMethod(LinkTouchMovementMethod.getInstance());
        if (commentator != null){
            ssb.append(commentator);
            ssb.setSpan(new TouchableSpan(REPLY),0,commentator.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        if (criticised != null){
            ssb.append(REPLY_HINT);
            ssb.append(criticised);
            ssb.setSpan(new TouchableSpan(REPLY_TO),
                        commentator.length()+REPLY_HINT.length(),
                        commentator.length()+REPLY_HINT.length()+criticised.length(),
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        if (content != null){
            ssb.append(":"+content);
        }
        this.setText(ssb,BufferType.NORMAL);
    }


    private class TouchableSpan extends ClickableSpan{

        private boolean mIsPressed = false;
        private int clickType;

        public TouchableSpan(int clickType) {
            this.clickType = clickType;
        }

        public void setIsPressed(boolean mIsPressed) {
            this.mIsPressed = mIsPressed;
        }

        @Override
        public void onClick(View widget) {
            switch (clickType){
                case REPLY:
                    if (commentTextViewListener != null) {
                        commentTextViewListener.OnReplyClick(getContext());
                    }
                    break;
                case REPLY_TO:
                    if (commentTextViewListener != null) {
                        commentTextViewListener.OnReplyToClick(getContext());
                    }
                    break;
            }
        }

        @Override
        public void updateDrawState(TextPaint ds) {
            super.updateDrawState(ds);
            ds.setColor(mUserHintColor);
            ds.bgColor = mIsPressed ? mUserHintBgPressedColor : mUserHintBgNormalColor;
            ds.setUnderlineText(false);
        }
    }

    /**
     * 自定义LinkMovementMethod
     */
    public static class LinkTouchMovementMethod extends LinkMovementMethod{

        static LinkTouchMovementMethod sInstance;
        private TouchableSpan mTouchableSpan;

        public static LinkTouchMovementMethod getInstance(){
            if (sInstance == null){
                sInstance = new LinkTouchMovementMethod();
            }
            return sInstance;
        }

        @Override
        public boolean onTouchEvent(TextView textView, Spannable spannable, MotionEvent event) {
            int action = event.getAction();
            if (action == MotionEvent.ACTION_DOWN){
                mTouchableSpan = getPressedSpan(textView,spannable,event);
                if (mTouchableSpan != null){
                    mIsLongClick = false;
                    mTouchableSpan.setIsPressed(true);
                    Selection.setSelection(spannable,spannable.getSpanStart(mTouchableSpan),
                            spannable.getSpanEnd(mTouchableSpan));
                    mIsInteriorClick = true;
                }else {
                    textView.setBackgroundColor(mViewBackgroundPressedColor);
                }
            } else if (action == MotionEvent.ACTION_UP){
                if (mTouchableSpan != null){
                    mTouchableSpan.setIsPressed(false);
                    if (!mIsLongClick){
                        super.onTouchEvent(textView, spannable, event);
                    }
                    mIsInteriorClick = true;
                }
                textView.setBackgroundResource(mViewBackgroundNormalColor);
                mTouchableSpan = null;
                Selection.removeSelection(spannable);
            }else if (action == MotionEvent.ACTION_MOVE){
                TouchableSpan touchableSpan = getPressedSpan(textView,spannable,event);
                if (mTouchableSpan != null && touchableSpan != mTouchableSpan){
                    mTouchableSpan.setIsPressed(false);
                    Selection.removeSelection(spannable);
                }
            }
            return Touch.onTouchEvent(textView, spannable, event);
        }

        private TouchableSpan getPressedSpan(TextView textView,Spannable spannable,MotionEvent event){
            int x = (int) event.getX();
            int y = (int) event.getY();

            x -= textView.getTotalPaddingLeft();
            y -= textView.getTotalPaddingTop();

            x += textView.getScrollX();
            y += textView.getScrollY();

            Layout layout = textView.getLayout();
            int line = layout.getLineForVertical(y);
            int off = layout.getOffsetForHorizontal(line, x);

            TouchableSpan[] link = spannable.getSpans(off, off, TouchableSpan.class);
            TouchableSpan touchedSpan = null;
            if (link.length > 0) {
                touchedSpan = link[0];
            }
            return touchedSpan;
        }
    }

    /**
     *  ClickableSpan的点击事件会跟TexView的点击事件冲突,
     *  TextView-onTouchEvent >> LinkMovementMethod-onTouchEvent >> TextView-performClick >> TextView-onClick
     *
     *  需要判断是否是内部点击了,如果是内部点击了则需要拦截事件再继续往下传。
     *  否则就将事件继续传下去
     */
    @Override
    public boolean performClick() {
        if (mIsInteriorClick) {
            return true;
        }
        return super.performClick();
    }

    /**
     * 监听长按事件 实现长按复制
     *
     * @return
     */
    @Override
    public boolean performLongClick() {
        mIsLongClick = true;
        this.setBackgroundColor(mViewBackgroundPressedColor);

        if (mIsLongClickCopyOf){
            ClipboardManager copy = (ClipboardManager) getContext()
                    .getSystemService(Context.CLIPBOARD_SERVICE);
            assert copy != null;
            copy.setPrimaryClip(ClipData.newPlainText(null, this.getText().toString()));
            Toast.makeText(getContext(), "复制成功", Toast.LENGTH_SHORT).show();
        }
        if (commentTextViewListener != null){
            commentTextViewListener.OnLongClick(getContext(),this);
        }
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mIsInteriorClick = false;
        return super.onTouchEvent(event);
    }


    public void setIsLongClickCopyOf(boolean mIsLongClickCopyOf) {
        this.mIsLongClickCopyOf = mIsLongClickCopyOf;
    }

    public void setCommentTextViewListener(CommentTextViewListener commentTextViewListener){
        this.commentTextViewListener = commentTextViewListener;
    }

}

接下来就是接口 。以及接口实现类

public interface CommentInterface{

    void OnReplyClick(Context context);

    void OnReplyToClick(Context context);

    void OnLongClick(Context context,UICommentTextView textView);

}
这里呢,可以根据自己做一些默认的操作

/**
 * Created by Peng on 2018/1/15.
 */
public abstract class CommentTextViewListener implements CommentInterface{

    @Override
    public void OnReplyToClick(Context context) {

    }

    @Override
    public void OnReplyClick(Context context) {

    }

    @Override
    public void OnLongClick(Context context, UICommentTextView textView) {

    }
}


接下来就是配置参数的了
(如图在values 资源文件下,创建attr_comment_text_view.xml)

然后将下列代码copy 进入即可



<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="UICommentTextView">
        <attr name="comment_UserHintColor" format="reference|color"/>
        <attr name="comment_UserHintBgPressedColor" format="reference|color"/>
        <attr name="comment_UserHintBgNormalColor" format="reference|color"/>
        <attr name="comment_ViewBackgroundPressedColor" format="reference|color"/>
        <attr name="comment_ViewBackgroundNormalColor" format="reference|color"/>
        <attr name="comment_IsLongClickCopyOf" format="reference|boolean"/>

    </declare-styleable>

</resources>


ok! 到这就已经代码贴完了,欢迎大家吐槽我写的不足的地方。不懂的地方也可以留言,本人看到了会回复的。

Demo地址:https://download.csdn.net/download/qq_35070105/10352996


猜你喜欢

转载自blog.csdn.net/qq_35070105/article/details/79065266