乐趣区

简洁高效可自定义的开源的Android评论控件CommentView

@TOC

目录

一、控件概述

1.1、介绍

CommentView 是一个简洁、高效、可自定义的开源的 Android 评论控件,反对 盖楼评论回复模式 下拉刷新评论 上拉加载更多评论 加载更多回复 等性能,可自定义(款式、数据模型、布局)、可轻松按需要扩大性能。

1.2、性能特点

性能特点
反对下拉刷新评论
反对上拉加载更多评论
反对加载更多回复
反对盖楼评论回复模式
可设置空数据视图、谬误视图
反对自定义数据模型
反对自定义款式配置器
反对自定义布局

1.3、效果图

GIF 压缩后成果变差,想亲自体验能够到上面的仓库下载安装包。

想要什么的款式成果能够自定义实现

默认款式成果(GIF)

自定义款式成果(自定义仿微信公众号评论)(GIF)

1.4、源码仓库

仓库 网址
码云 https://gitee.com/jidcoo/CommentView
GitHub https://github.com/Jidcoo/CommentView
Jcenter(Maven) https://bintray.com/longyun/maven/CommentView

二、框架类解析

2.1、我的项目目录构造


2.2、我的项目整体框架

CommentView 只负责对外提供业务办法,所有的业务实现和外围代码都在 com.jidcoo.android.widget.commentview.operator 包和 com.jidcoo.android.widget.commentview.adapter 包。com.jidcoo.android.widget.commentview.callback 包是业务和控件的桥接包。

2.3、框架合成

2.3.1、数据模型类(Model)

整体框架

2.3.1.1、PagerEnable(分页)
/**
 * 分页模型 <br>
 * <br>
 * 在 Android 端只实现为对分页数据的 Get/Set 操作 <br>
 * <br>
 * 具体的分页逻辑应该由后端实现,客户端只负责对数据的解决 <br>
 * <br>
 * @author Jidcoo
 */
public class PagerEnable {
    /**
     * 以后页码
     */
    public int currentPage;
    /**
     * 每一页数据的大小
     */
    private int pageSize;
    /**
     * 总页数
     */
    public int totalPages;
    /**
     * 数据总数
     */
    public int totalDataSize;
    /**
     * 下一个页码
     */
    public int nextPage;
    /**
     * 上一个页码
     */
    public int prefPage;
    //
    // 省略大量 Get()/Set() 办法
    //
}

PagerEnable 类是一个分页模型,是 我的项目数据模型中十分重要的一个基类,评论数据抽象模型 AbstractCommentModel、CommentEnable 都继承自 PagerEnable 类。在业务类的外围代码中都须要用到 PagerEnable 类中的页码数据和办法。

在 Android 端不波及具体分页逻辑,具体分页逻辑在后端实现。留神:在理论应用中,如果要实现分页加载(更多评论数据、更多回复数据),那么要展现的数据必须蕴含这些分页数据字段。 比方在 json 数据中必须蕴含这些数据,分页性能能力真正无效。也就是说无论你用什么作为数据,都必须在数据中蕴含相干分页数据字段。继承了 PagerEnable 类的所有类对于的数据都要蕴含相干分页数据字段

2.3.1.2、ReplyEnable(回复数据基类)
/**
 * 自定义回复模型必须继承自此类
 * @author Jidcoo
 */
public class ReplyEnable {}

ReplyEnable 类是回复数据模型的基类,自定义回复模型必须继承自此类 。能够看出此类 没有任何的继承关系

可能有人会问,回复数据不是须要分页吗?为什么 ReplyEnable 类没有继承自 PagerEnable 分页模型类?没有分页数据回复数据如何分页?首先如果要实现回复数据分页加载,那么 回复数据是须要分页的 。然而 回复数据的分页数据应该属于它所在评论 (CommentEnable) 的那一级中 ,而不是在回复数据自身上,因为在 分页数据在回复模型中没有任何意义 。是 通过回复数据所在的那个评论模型 (CommentEnable) 中体现回复数据的分页状况

所有回复数据的分页加载都是基于它所在的评论模型所决定和管制的。而CommentEnable 类正是继承自 PagerEnable 类,继承自 PagerEnable 类的惟一目标就是用来管制回复数据的分页性能。了解这段话就可能晓得为什么 ReplyEnable 类只是一个空类了。

自定义回复数据模型例子:

/**
 * 首先继承自 ReplyEnable 类
 * 而后设置回复模型中所须要的数据就能够了
 */
public class Reply extends ReplyEnable {
      public String userName;
      public String reply;
      .....
      设置更多具体的属性,比方工夫、点赞数之类的数据
      .....
}
2.3.1.3、CommentEnable(评论数据抽象类)
/**
 * <p> 自定义评论模型抽象类 </p>
 * 自定义评论模型必须继承自此抽象类
 * @author Jidcoo
 */
public abstract class CommentEnable extends PagerEnable{

    /**
     * 必须实现该办法并确保返回值非 NULL
     * @return
     */
    public abstract <R extends ReplyEnable> List<R> getReplies();}

CommentEnable 是一个继承自 PagerEnable 类的抽象类。继承自 PagerEnable 类的惟一目标就是用来管制回复数据的分页性能,所以继承自此类的实体类就具能够反对所在评论的回复数据的分页加载。

自定义评论数据模型 必须继承自 CommentEnable 类并实现 getReplies()形象办法 getReplies() 办法十分重要,必须实现。该办法返回一个 List<? extend ReplyEnable> 的 list,这个 list 的元素是继承自 ReplyEnable 的自定义的回复数据模型实体类。如第二点中的例子 Reply 类。

自定义评论数据模型例子:

/**
 * 首先继承自 CommentEnable 类
 * 而后实现形象办法 getReplies(), 返回一个回复数据的 List
 * 而后设置回复模型中所须要的数据就能够了
 */
public class Comment extends CommentEnable{
      public List<Reply> replies;
      public String userName;
      public String comment;
      .....
      设置更多具体的属性,比方工夫、点赞数之类的数据
      .....
      /*@Override
      public List<R> getReplies() {return null;}*/
      // 必须实现 getReplies()办法。@Override
      public  List<Reply> getReplies() {return replies;}
      /**
       * 首先继承自 ReplyEnable 类
       * 而后设置回复模型中所须要的数据就能够了
       */
      public class Reply extends ReplyEnable {
            public String userName;
            public String reply;
            .....
            设置更多具体的属性,比方工夫、点赞数之类的数据
            .....
      }
}

留神:CommentEnable 类中 getReplies()的原型是这样的:

@Override
public List<R> getReplies() {return null;}

所以实现 getReplies()办法的时候只须要把泛型 R 改为本人定义的回复数据模型类就能够了,而后在办法中返回这个实体类的汇合。

2.3.1.4、AbstractCommentModel(评论数据总抽象类)
/**
 * 数据抽象模型 <p></p>
 * 自定义模型必须继承此形象模型,并实现其中的办法 <p></p>
 * <u> 留神:应用自定义数据类型就必须自定义布局实现,否则会抛出数据模型的 java.lang.ClassCastException 异样 </u><br></br>
 * AbstractCommentModel 中传入的泛型 <C extends CommentEnable> 必须继承自 CommentEnable, 查看{@link CommentEnable}
 * @param <C> 自定义的评论数据模型
 * @author Jidcoo
 */
public  abstract class AbstractCommentModel <C extends CommentEnable> extends PagerEnable{
    /**
     * 必须实现该办法并确保返回值非 NULL
     * @return
     */
    public abstract List<C> getComments() ;}

AbstractCommentModel 类是评论模型抽象类,继承自 PagerEnable 类 用来管制评论数据的分页性能 。同时它是一个泛型抽象类,泛型承受的类 必须是继承自 CommentEnable 的类,比方第三点中的例子 Comment 类。

同样的,实现自定义的数据模型 必须继承自 AbstractCommentModel 类并实现 getComments 形象办法 (设计思维与 CommentEnable 类一样)。getComments() 办法十分重要,必须实现 。该办法返回一个 List<? extend CommentEnable> 的 list,这个 list 的元素是继承自 CommentEnable 的自定义的评论数据模型实体类。如第三点中的例子 Comment 类。
留神:应用自定义数据类型就必须自定义布局实现,否则会抛出数据模型的 java.lang.ClassCastException 异样。起因能够查看 defaults 包下的 DefaultItemBuilder 类对于默认布局的实现办法。

AbstractCommentModel 实际上是业务办法中应用到的最外层的数据模型类了。查看 CommentView 的源码中的业务办法就能够晓得,次要的无关数据的业务办法承受的参数都是 AbstractCommentModel,也就是说承受继承自此抽象类的数据模型。

自定义模型例子:

/**
 * 首先继承自形象泛型类 AbstractCommentModel<C>
 * 其中泛型 C 用自定义的评论模型类替换就能够了
 * 而后实现形象办法 getComments(), 返回一个评论数据的 List
 */
public class CommentModel extends AbstractCommentModel<CommentModel.Comment> {
    public List<Comment> comments;

    // 必须实现 getComments()办法并确保返回值非 NULL
    @Override
    public List<Comment> getComments() {return comments;}

    /**
 * 首先继承自 CommentEnable 类
 * 而后实现形象办法 getReplies(), 返回一个回复数据的 List
 * 而后设置回复模型中所须要的数据就能够了
 */
public class Comment extends CommentEnable{
      public String userName;
      public String comment;
      public List<Reply> replies;

      /*@Override
      public List<R> getReplies() {return null;}*/
      @Override
      public  List<Reply> getReplies() {return replies;}
      /**
       * 首先继承自 ReplyEnable 类
       * 而后设置回复模型中所须要的数据就能够了
       */
      public class Reply extends ReplyEnable {
            public String userName;
            public String reply;
      }
}
}

在自定义模型中要继承自形象泛型类 AbstractCommentModel < C extends CommentEnable>

public class CommentModel extends AbstractCommentModel<C>
    @Override
    public List<C> getComments() {return null;}

这里的泛型 C 用自定义的评论数据模型类(如第三点的例子 Comment 类)替换就能够了。

其实在自定义模型类中做的事件并不多,因为须要的 Comment 类、Reply 类之前都曾经自定义好了。所以当初就只须要在自定义模型类中继承自 AbstractCommentModel<C>,并把泛型 C 替换成本人 Comment 类,最初实现形象办法 getComments()就能够了。留神:getComments()办法必须实现并返回对应的 List,被确保返回的这个 List 非 null

2.3.1.5、总结

好了,到当初为止,CommentView 控件的数据模型就剖析完了。好长篇幅。为什么呢?因为这个数据模型对于整个框架来说太重要了。必须了解好数据模型能力轻松应用这个控件。所以必须详细分析整个数据模型。

2.3.2、ViewHolder 类

ViewHolder 类是一个抽象类,是 对于自定义回复布局的时候应用 的,自定义评论布局不须要继承自此类。ViewHolder 位于 com.jidcoo.android.widget.commentview.view 包下。

自定义评论布局 ViewHolder 类没有任何限度和要求 不须要任何继承。所以这里不展现例子代码了,例子能够查看 defaults 包下的 DefaultCommentHolder 类。

然而对于自定义回复布局,有 四点必须 不按要求就报错 ):
1、 必须应用 ViewHolder 机制
2、 应用的 ViewHolder 必须继承自 com.jidcoo.android.widget.commentview.view 包下 ViewHolder 抽象类。
3、自定义的回复布局中最外层布局必须为 LinearLayout
4、并且这个最外层的 LinearLayout 的 android:id 属性必须设置为“reply_rootView”,即 android:id=”@+id/reply_rootView”

这四点必须怎么来的呢,上面看 ViewHolder 类的代码:

/**
 * 自定义回复布局必须继承此抽象类并在构造方法中调用父类构造方法,否则会报错。<p>
 * <br></br>
 * 在自定义回复布局中最外层必须应用 LinearLayout 并将布局 id 设置为“reply_rootView”,否则会报错。<p>
 * @author Jidcoo
 */
public abstract class ViewHolder {
    /**
     * 自定义布局这个 view 必须为非空
     */
    public LinearLayout rootView;
    public ViewHolder(View view){
        try {rootView=view.findViewById(R.id.reply_rootView);
        }catch (Exception e){throw  new RuntimeException("If you use a custom layout, the outermost layout must be a LinearLayout, and you need to set its id attribute value to \"reply_rootView\"");
        }
    }
}

在 ViewHolder 这个抽象类中有一个 LinearLayout 变量 rootView,而后在构造方法中会 在传进来的自定义布局的 view 外面通过 findViewById()实例化 rootView。所以当 找不到这个 id 或者这个 id 对应的类型不是 LinearLayout 的时候会抛出 RuntimeException 异样

至于为什么要实例化 rootView 这个变量,能够看 com.jidcoo.android.widget.commentview.adapter 包下的 ViewAdapter 类的具体代码实现就晓得了。这里不具体开展。

自定义回复布局时应用的 ViewHolder 的例子:

/**
 * 创立类继承自抽象类 ViewHolder
 * 而后在带参构造方法中显式调用父级构造方法 super(view)把 view 传进去
 * 而后再实例化本人自定义的布局控件
 */
public class ReplyItemViewHolder extends ViewHolder {
    public TextView replyTextView;
    //……增加本人须要的控件
    //……
    //……增加本人须要的控件
    
    public ReplyItemViewHolder(View view) {super(view);
        // 实例化对应的控件
        replyTextView=view.findViewById(R.id.replyTextView);
        
    }
}

2.3.3、回调类(Callback)

2.3.3.1、CustomCommentItemCallback(自定义评论布局回调)
/**
 * 自定义评论布局的回调 <p></p>
 * 相当于 Adapter 的 getView()办法 <p></p>
 * 与 Adapter 的 getView()办法应用一样 <p></p>
 * 泛型接口中的泛型对应评论数据模型,即继承在 CommentEnable,查看{@link CommentEnable}
 * @author Jidcoo
 */
public interface CustomCommentItemCallback<C extends CommentEnable> {

    /**
     * 相当于 adapter 中的 getView()办法
     * @param groupPosition Item 所在 groupPosition
     * @param comment 泛型评论数据
     * @param inflater  LayoutInflater 实例(非空)* @param convertView View
     * @param parent
     * @return
     */
    View buildCommentItem(int groupPosition, C comment, LayoutInflater inflater, View convertView, ViewGroup parent);
}

CustomCommentItemCallback 是一个自定义评论布局的泛型回调,非必须回调 ,当须要自定义评论布局的时候实现这个回调, 回调中的 buildCommentItem()办法相当于 Adapter 中的 getView()办法 ,在 buildCommentItem() 中应用自定义的布局即可。

CustomCommentItemCallback< C extends CommentEnable> 中的泛型 C 是你应用的评论数据模型,即 该回调承受的类必须继承自 CommentEnable。引入自定义布局须要的 LayoutInflater 实例曾经保障是非 null 的,间接应用即可,不须要外创立一个新的实例升高性能。留神:在 实现该办法时尽量应用 ViewHolder 机制,否则控件的性能可能会降落。

当须要自定义评论布局的时候实现这个回调。

例子

/**
 * 自定义评论布局
 * 实现 CustomCommentItemCallback<C> 回调
 * 把自定义评论模型 Comment 放入泛型参数中
 * 而后实现 buildCommentItem()办法进行自定义布局
 */
public class CustomCommentItem implements CustomCommentItemCallback<Comment> {
    @Override
    public View buildCommentItem(int groupPosition,Comment comment, LayoutInflater inflater, View convertView, ViewGroup parent) {
        // 应用 ViewHolder 机制
        // 自定义评论布局的 ViewHolder 没有任何要求,不须要任何继承
        // 为了更好的性能,尽量应用 ViewHolder 机制
        CommentViewHolder commentViewHolder=null;
        if(convertView==null){
            // 引入自定义布局
            convertView=inflater.inflate(R.layout.my_commentItem_layout);
            // 实例化 CommentViewHolder
            commentViewHolder=new CommentViewHolder(convertView);
            convertView.setTag(commentViewHolder);
        }else{commentViewHolder=(CommentViewHolder)convertView.getTag();}
        // 对控件进行操作
        //setText()……
        // 对控件进行操作
        return convertView;
    }
}
2.3.3.2、CustomReplyItemCallback(自定义回复布局回调)
/**
 * 自定义回复布局的回调 <p></p>
 * 相当于 Adapter 的 getView()办法 <p></p>
 * 与 Adapter 的 getView()办法应用一样 <p></p>
 * 泛型接口中的泛型对应回复数据模型,即继承在 ReplyEnable,查看{@link ReplyEnable}<p></p>
 * 留神:* <br></br>
 * 布局:<p>
 * 1、自定义布局 xml 中最外层布局必须是 LinearLayout 并且把最外层布局 id 设置为 reply_rootView<p>
 * ViewHolder:<p>
 * 1、在 buildReplyItem()中自定义布局初始化时,必须应用 ViewHolder 机制 <p>
 * 2、初始化过程中,自定义 Holder 必须继承自 com.jidcoo.android.widget.commentview.view.ViewHolder, 查看{@link ViewHolder}<p>
 * @author Jidcoo
 */
public interface CustomReplyItemCallback<R extends ReplyEnable> {

    /**
     * 相当于 adapter 中的 getView()办法
     * @param groupPosition 所在父级地位
     * @param childPosition 所在位置
     * @param isLastReply 是否是最初一条评论
     * @param convertView View
     * @param reply 泛型回复数据
     * @param inflater  LayoutInflater 实例(非空)* @param parent
     * @return
     */
    View buildReplyItem(int groupPosition, int childPosition, boolean isLastReply, R reply, LayoutInflater inflater, View convertView, ViewGroup parent);
}

CustomReplyItemCallback 是一个自定义回复布局的泛型回调,非必须回调 ,当须要自定义回复布局的时候实现这个回调, 回调中的 buildReplyItem()办法相当于 Adapter 中的 getView()办法 ,在 buildReplyItem() 中应用自定义的布局即可。

CustomReplyItemCallback< R extends ReplyEnable> 中的泛型 R 是你应用的回复数据模型,即 该回调承受的类必须继承自 ReplyEnable。引入自定义布局须要的 LayoutInflater 实例曾经保障是非 null 的,间接应用即可,不须要外创立一个新的实例升高性能。留神:在 实现 buildReplyItem()办法时有四点必须(不按要求就报错):

1、必须应用 ViewHolder 机制
2、 应用的 ViewHolder 必须继承自 com.jidcoo.android.widget.commentview.view 包下 ViewHolder 抽象类。
3、自定义的回复布局中最外层布局必须为 LinearLayout
4、并且这个最外层的 LinearLayout 的 android:id 属性必须设置为“reply_rootView”,即 android:id=”@+id/reply_rootView”

这里的 ViewHolder 上边说过了,这里不再反复。在 ViewAdapter 中有一段代码是用来对 ViewHolder 做校验的:

        if(convertView.getTag() == null) {throw new RuntimeException("You should call convertView.getTag() method to use Holder instance as the tag of convertView");
        }else{Object object = convertView.getTag();
            if(object instanceof ViewHolder) {//some core code}else{throw new RuntimeException("The ReplyHolder must extent from ViewHolder");
            }
        }

当应用自定义布局时,它会依据你返回的的自定义 convertView 进行 getTag(),如果返回 null,就抛出异样,所以 在应用自定义布局时必须应用 convertView.setTag()把 Holder 保存起来(ViewHolder 机制)

当 getTag()不为空的时候,又会去 判断返回的对象是不是继承自 ViewHolder,如果不是,就抛出异样

当须要自定义回复布局的时候实现这个回调。

例子

/**
 * 自定义评论布局
 * 实现 CustomReplyItemCallback<R> 回调
 * 把自定义回复模型 Reply 放入泛型参数中
 * 而后实现 buildReplyItem()办法进行自定义布局
 */
public class CustomReplyItem implements CustomReplyItemCallback<Reply> {

    @Override
    public View buildReplyItem(int groupPosition, int childPosition, boolean isLastReply, Reply reply, LayoutInflater inflater, View convertView, ViewGroup parent) {
        // 必须应用 ViewHolder 机制
        // 自定义 ReplyItemViewHolder 必须继承自 com.jidcoo.android.widget.commentview.view.ViewHolder
        // 在自定义回复布局中最外层必须应用 LinearLayout
        // 并将这个 LinearLayout 的 id 设置为“reply_rootView”,否则会报错。ReplyItemViewHolder replyItemViewHolder=null;
        if(convertView==null){
            // 引入自定义布局
            convertView=inflater.inflate(R.layout.my_replyItem_layout);
            // 实例化 ReplyItemViewHolder
            replyItemViewHolder=new ReplyItemViewHolder(convertView);
            // 必须把 ReplyItemViewHolder 缓存在 convertView 中
            // 否则报错
            convertView.setTag(replyItemViewHolder);
            // 必须把 ReplyItemViewHolder 缓存在 convertView 中
        }else{replyItemViewHolder=(ReplyItemViewHolder)convertView.getTag();}
        // 对控件进行操作
        //setText()……
        // 对控件进行操作
        return convertView;
    }
}
2.3.3.3、OnPullRefreshCallback(下拉刷新回调)
/**
 * CommentView 下拉刷新回调
 * @author Jidcoo
 */
public interface OnPullRefreshCallback {
    /**
     * 刷新回调
     */
    void refreshing();
    /**
     * 刷新实现回调
     */
    void complete();

    /**
     * 刷新失败
     * @param msg 错误信息
     */
    void failure(String msg);
}

OnPullRefreshCallback 是下拉刷新回调,非必须回调。当实现了这个回调后能够进行下拉刷新,不实现就无奈下拉刷新。看具体需要。

须要下拉刷新性能时实现这个回调。

例子:

public class MyOnPullRefreshCallback implements OnPullRefreshCallback {
    @Override
    public void refreshing() {
        // 该办法被调用,示意控件正在刷新状态
        // 实现你的刷新逻辑
        //commentView.refreshComplete(AbstractCommentModel model): 刷新数据实现后调用
        //commentView.refreshFailed(String,boolean): 刷新呈现谬误时调用,能够管制是否显示谬误视图
    }

    @Override
    public void complete() {}

    @Override
    public void failure(String msg) {// 当刷新失败后显示调用 commentView.refreshFailed(String,boolean)办法后
        // 这个办法会被调用
        //msg 是 refreshFailed()办法中传进来的错误信息}
}
2.3.3.4、OnCommentLoadMoreCallback(上拉加载更多回调)
/**
 * CommentView 加载更多评论回调
 * @author Jidcoo
 */
public interface OnCommentLoadMoreCallback{

    /**
     * 上拉加载更多评论回调
     * @param currentPage 以后页码
     * @param willLoadPage 下一个页码
     * @param isLoadedAllPages 是否曾经加载完所有数据
     */
    void loading(int currentPage,int willLoadPage,boolean isLoadedAllPages);

    /**
     * 上拉加载更多评论实现
     */
    void complete();

    /**
     * 加载失败
     * @param msg 错误信息
     */
    void failure(String msg);
}

OnCommentLoadMoreCallback 是上拉加载更多评论回调,非必须回调。当实现了这个回调后能够进行上拉加载更多评论,不实现就无奈上拉加载更多评论。看具体需要。

须要上拉加载更多评论性能时实现这个回调就能够了,和 OnPullRefreshCallback 的例子基本一致。具体应用例子能够查看相干源码。

2.3.3.5、OnReplyLoadMoreCallback(加载更多回复回调)
/**
 * CommentView 加载更多回复回调 <p></p>
 * 泛型接口中的泛型 R 是回复数据模型,必须继承自 ReplyEnable,查看{@link ReplyEnable}
 * @author Jidcoo
 */
public interface OnReplyLoadMoreCallback<R extends ReplyEnable> {

    /**
     * 加载更多回复回调
     * @param reply 对应回复的数据
     * @param willLoadPage
     */
    void loading(R reply, int willLoadPage);

    /**
     * 加载更多回复实现回调
     */
    void complete();

    /**
     * 加载失败
     * @param msg 错误信息
     */
    void failure(String msg);
}

OnReplyLoadMoreCallback 是一个泛型回调,是加载更多回复回调,非必须回调。OnReplyLoadMoreCallback< R extends ReplyEnable> 承受一个继承自 ReplyEnable 类的自定义回复数据模型类。具体应用例子能够查看相干源码。

2.3.3.6、OnScrollCallback(滚动事件回调)
/**
 * CommentView 滚动事件回调
 * @author Jidcoo
 */
public interface OnScrollCallback {
    /**
     * 滚动回调
     * @param view
     * @param firstVisibleItem
     * @param visibleItemCount
     * @param totalItemCount
     */
    void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int
            totalItemCount);

    /**
     * 滚动状态回调
     * @param view
     * @param scrollState
     */
    void onScrollStateChanged(AbsListView view,int scrollState);

    /**
     * 滚动回调
     * @param v
     * @param scrollX
     * @param scrollY
     * @param oldScrollX
     * @param oldScrollY
     */
    void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY);

}

OnScrollCallback 提供了控件的所有滚动事件的回调,非必须回调。能够通过实现这个回调来监听控件滚动事件。

2.3.3.7、OnItemClickCallback(Item 点击事件回调)
/**
 * CommentView 中评论 Item 和回复 Item 点击事件回调
 * 泛型接口中的 C、R 泛型:<p></p>
 * 1、C 是评论数据模型,必须继承自 CommentEnable, 查看{@link CommentEnable}<p></p>
 * 2、R 是回复数据模型,必须继承自 ReplyEnable, 查看{@link ReplyEnable}<p></p>
 * @author Jidcoo
 */
public interface OnItemClickCallback<C extends CommentEnable,R extends ReplyEnable> {
    /**
     * 评论 Item 点击回调事件
     * @param position 被点击 Item 的地位
     * @param comment 被点击 Item 所对应的数据
     * @param view 被点击 Item 的 View
     */
    void commentItemOnClick(int position, C comment, View view);

    /**
     * 回复 Item 点击回调事件
     * @param c_position 被点击 Item 所在的父级地位
     * @param r_position 被点击 Item 所在位置
     * @param reply 被点击 Item 所对应的数据
     * @param view 被点击 Item 的 View
     */
    void replyItemOnClick(int c_position, int r_position, R reply, View view);
}

OnItemClickCallback 类是一个承受泛型参数的Item 点击事件回调,OnItemClickCallback<C extends CommentEnable,R extends ReplyEnable> 中泛型 C、R 对应的就是自定义评论数据模型和回复数据模型。当控件中评论 Item 和回复 Item 被点击时,回调中绝对应的 commentItemOnClick 和 replyItemOnClick 办法就会被调用。

须要监听控件 Item 的点击事件就实现这个接口。具体应用例子能够查看相干源码。

2.3.3.8、CallbackBuilder(回调集)
    public final class CallbackBuilder {
        ///////***Callback***//////
        public OnPullRefreshCallback onPullRefreshCallback;// 下拉刷新回调
        public OnCommentLoadMoreCallback onCommentLoadMoreCallback;// 加载更多评论回调
        public OnReplyLoadMoreCallback onReplyLoadMoreCallback;// 加载更多回复回调
        public OnItemClickCallback onItemClickCallback;// 点击事件回调
        public OnScrollCallback onScrollCallback;// 滚动事件回调
        public CustomCommentItemCallback customCommentItemCallback;// 自定义评论布局回调
        public CustomReplyItemCallback customReplyItemCallback;// 自定义回复布局回调
        ///////***Callback***//////
        public CallbackBuilder setOnPullRefreshCallback(OnPullRefreshCallback onPullRefreshCallback) {
            this.onPullRefreshCallback = onPullRefreshCallback;
            return this;
        }

        public CallbackBuilder setOnCommentLoadMoreCallback(OnCommentLoadMoreCallback onCommentLoadMoreCallback) {
            this.onCommentLoadMoreCallback = onCommentLoadMoreCallback;
            return this;
        }

        public CallbackBuilder setOnReplyLoadMoreCallback(OnReplyLoadMoreCallback onReplyLoadMoreCallback) {
            this.onReplyLoadMoreCallback = onReplyLoadMoreCallback;
            return this;
        }

        public CallbackBuilder setOnItemClickCallback(OnItemClickCallback onItemClickCallback) {
            this.onItemClickCallback = onItemClickCallback;
            return this;
        }

        public CallbackBuilder setOnScrollCallback(OnScrollCallback onScrollCallback) {
            this.onScrollCallback = onScrollCallback;
            return this;
        }

        public CallbackBuilder customCommentItem(CustomCommentItemCallback customCommentItemCallback) {
            this.customCommentItemCallback = customCommentItemCallback;
            return this;
        }

        public CallbackBuilder customReplyItem(CustomReplyItemCallback customReplyItemCallback) {
            this.customReplyItemCallback = customReplyItemCallback;
            return this;
        }
        public CommentView buildCallback() {return initialize(this);
        }
    }

CallbackBuilder 是一个构建控件的所有回调的 Builder 类,是 CommentView 类中的外部类。下面说到的所有的 Callback 都须要通过这个 Builder 类进行设置,构建回调须要获取这个 Builder 类的实例,而后再往这个 Builder 类设置须要的回调。

获取这个 Builder 类的实例通过 CommentView.callbackBuilder()办法获取。当 Builder 实例为 NULL 时返回一个新实例,不为 NULL 就返回原来构建的实例。

能够看到,在 buildCallback()办法中会调用 CommentView 的 initialize()办法对 Builder 类的回调实例进行初始化和进一步装载。留神:无论是否须要设置回调,buildCallback()办法必须调用,如果不调用 buildCallback()办法,控件处于未初始化状态,不会展现任何数据和成果。。具体起因可自行查看 com.jidcoo.android.widget.commentview.operator 包下的 CommentViewOperator 类源码。

也就是说,就算在不须要设置任何回调的状况下,buildCallback()都必须调用。调用如下:

commentView.callbackBuilder().buildCallback();

初始化回调例子:

CommentView commentView;
commentView.callbackBuilder()
           .setOnPullRefreshCallback(你的回调实例)
           .onItemClickCallback(你的回调实例)
           ......
           // 设置实现后必须调用 CallbackBuilder 的 buildCallback()办法,否则设置的回调有效,控件也无奈失常显示。// 无论是否设置回调,buildCallback()办法都必须调用。.buildCallback();
2.3.3.9、总结

好了,到当初为止,CommentView 控件的回调类根本介绍实现。写的时候感觉非常啰嗦,但最初还是写下来了。因为这些回调类尽管都是非必须回调,然而 想实现更多功能都须要用到这些回调

2.4、款式配置器

/**
 * 非可自定义控件款式配置器
 * <p> 该款式配置器针对非自定义控件的款式的具体配置 </p>
 * <p> 可依据具体需要配置这部分的控件的款式 </p>
 * <p> 自定义款式配置器必须继承自本类 </p>
 * <br></br>
 * <h3> 款式变量阐明:</h3>
 * <p>1、refreshViewColor </p>
 * <p> 类型:String</p>
 * <p> 阐明:下拉刷新后呈现的圆形滚动条的色彩 </p>
 * <p> 赋值样例:#000000</p>
 * <p>2、lmv_showText(失常显示状态) </p>
 * <p> 类型:String</p>
 * <p> 阐明:当回复数据 Item 能够加载更多(分页加载)时,在最初一条回复 Item 的 View 上面显示的文字 </p>
 * <p> 赋值样例:开展更多回复 </p>
 * <p>3、lmv_textSize </p>
 * <p> 类型:int</p>
 * <p> 阐明:第二条阐明中的文字大小 </p>
 * <p> 赋值样例:14</p>
 * <p>4、lmv_textColor </p>
 * <p> 类型:String</p>
 * <p> 阐明:第二条阐明中的文字色彩 </p>
 * <p> 赋值样例:#000000</p>
 * <p>5、lmv_textStyle </p>
 * <p> 类型:Typeface,查看{@link Typeface}</p>
 * <p> 阐明:第二条阐明中的文字款式(失常、斜体、加粗)</p>
 * <p> 赋值样例:Typeface.defaultFromStyle(Typeface.NORMAL)</p>
 * <p>6、lmv_loading_showText(加载中状态) </p>
 * <p> 类型:String</p>
 * <p> 阐明:当回复数据 Item 能够加载更多(分页加载)时,在最初一条回复 Item 的加载更多 View 被点击后显示的文字 </p>
 * <p> 赋值样例:加载中 </p>
 * <p>7、lmv_loading_textSize </p>
 * <p> 类型:int</p>
 * <p> 阐明:第六条阐明中的文字大小 </p>
 * <p> 赋值样例:14</p>
 * <p>8、lmv_loading_textColor </p>
 * <p> 类型:String</p>
 * <p> 阐明:第六条阐明中的文字色彩 </p>
 * <p> 赋值样例:#000000</p>
 * <p>9、lmv_loading_textStyle </p>
 * <p> 类型:Typeface,查看{@link Typeface}</p>
 * <p> 阐明:第六条阐明中的文字款式(失常、斜体、加粗)</p>
 * <p> 赋值样例:Typeface.defaultFromStyle(Typeface.NORMAL)</p>
 * <p>10、lmv_loading_progressBarColor </p>
 * <p> 类型:String</p>
 * <p> 阐明:当最初一条回复 ItemView 的可加载更多 View 状态为正在加载状态时,* 第六条阐明中的文字左边会显示一个圆形 progressBar 以加强 UI 加载成果,* 该属性是这个 progressBar 的色彩值 </p>
 * <p> 赋值样例:#000000</p>
 * <p>11、lmv_loading_progressBarSize </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第十条阐明中的 progressBar 控件的大小尺寸 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(14)</p>
 * <p>12、lmv_adjustMargins </p>
 * <p> 类型:Boolean(默认为 false)</p>
 * <p> 阐明:是否调整最初一条回复 Item 的加载更多 View 的边距,如果自定义回复布局,可能须要
 * 调整这个 View 的边距来使布局更好看,个别状况下都须要调整边距,所以这个属性个别都为 true</p>
 * <p> 赋值样例:true</p>
 * <p>13、lmv_adjustMarginsLeft </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第十二条阐明中的 view 的右边距,如果 lmv_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(14)</p>
 * <p>14、lmv_adjustMarginsTop </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第十二条阐明中的 view 的上边距,如果 lmv_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(14)</p>
 * <p>15、lmv_adjustMarginsRight </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第十二条阐明中的 view 的左边距,如果 lmv_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(14)</p>
 * <p>16、lmv_adjustMarginsBottom </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第十二条阐明中的 view 的下边距,如果 lmv_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(14)</p>
 * <p>17、dividerColor </p>
 * <p> 类型:String</p>
 * <p> 阐明:控件 Item 的分割线色彩(蕴含一级分割线和二级分割线)</p>
 * <p> 赋值样例:#000000</p>
 * <p>18、dividerHeight </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:控件 Item 的分割线高度(蕴含一级分割线和二级分割线)</p>
 * <p> 赋值样例:ViewUtil.dpToPx(1),高度个别为 1dp</p>
 * <p>19、isDrawChildDivider </p>
 * <p> 类型:Boolean(默认为 false)</p>
 * <p> 阐明:是否绘制某一条评论下的最初一条回复 Item 与下一条评论的 Item 的 <u> 分割线 </u>,默认不绘制,* 可依据具体须要抉择是否绘制 </p>
 * <p> 赋值样例:true</p>
 * <p>20、c_divider_adjustMargins </p>
 * <p> 类型:Boolean(默认为 false)</p>
 * <p> 阐明:是否调整第十七条阐明中的分割线的边距,如果 isDrawDivider 为 false, 则此属性有效。* 因为第十九条阐明中的分割线宽度固定为 match_parent(即铺满全屏),然而能够通过调整分割线的边距
 * 来间接调整分割线的宽度和地位,可依据具体须要抉择是否调整分割线的边距 </p>
 * <p> 赋值样例:true</p>
 * <p>21、c_divider_adjustMarginsLeft </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第十九条阐明中的分割线的右边距,如果 divider_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(1)</p>
 * <p>22、c_divider_adjustMarginsTop </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第十九条阐明中的分割线的上边距,如果 divider_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(1)</p>
 * <p>23、c_divider_adjustMarginsRight </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第十九条阐明中的分割线的左边距,如果 divider_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(1)</p>
 * <p>24、c_divider_adjustMarginsBottom </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第十九条阐明中的分割线的下边距,如果 divider_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(1)</p>
 * <p>25、f_divider_adjustMargins </p>
 * <p> 类型:Boolean(默认为 false)</p>
 * <p> 阐明:是否调整评论 item 的分割线的边距 </p>
 * <p> 赋值样例:true</p>
 * <p>26、f_divider_adjustMarginsLeft </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:评论 item 的分割线的右边距 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(1)</p>
 * <p>27、f_divider_adjustMarginsTop </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:评论 item 的分割线的上边距 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(1)</p>
 * <p>28、f_divider_adjustMarginsRight </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:评论 item 的分割线的左边距 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(1)</p>
 * <p>29、f_divider_adjustMarginsBottom </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:评论 item 的分割线的下边距 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(1)</p>
 * <p>30、lm_footerProgressBarSize </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:上拉刷新时,控件底部会有一个圆形 ProgressBar 来减少加载中的 UI 成果,此属性为 ProgressBar 的大小 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(1)</p>
 * <p>31、lm_footerProgressBarColor </p>
 * <p> 类型:String</p>
 * <p> 阐明:第三十条阐明中的 ProgressBar 的色彩 </p>
 * <p> 赋值样例:#000000</p>
 * <p>32、lm_footerProgressBar_adjustMargins </p>
 * <p> 类型:Boolean(默认为 false)</p>
 * <p> 阐明:是否调整第三十条阐明中的 ProgressBar 的边距 </p>
 * <p> 赋值样例:true</p>
 * <p>33、lm_footerProgressBar_adjustMarginsLeft </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第三十条阐明中的 ProgressBar 的右边距,如果 lm_footerProgressBar_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(14)</p>
 * <p>34、lm_footerProgressBar_adjustMarginsTop </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第三十条阐明中的 ProgressBar 的上边距,如果 lm_footerProgressBar_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(14)</p>
 * <p>35、lm_footerProgressBar_adjustMarginsRight </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第三十条阐明中的 ProgressBar 的左边距,如果 lm_footerProgressBar_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(14)</p>
 * <p>36、lm_footerProgressBar_adjustMarginsBottom </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第三十条阐明中的 ProgressBar 的下边距,如果 lm_footerProgressBar_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(14)</p>
 * <p>37、lm_footer_text</p>
 * <p> 类型:String</p>
 * <p> 阐明:当所有数据加载实现后控件底部 textView 显示的文字 </p>
 * <p> 赋值样例:哈哈,所有评论都在这了 </p>
 * <p>38、lm_footer_textColor</p>
 * <p> 类型:String</p>
 * <p> 阐明:第三十七条阐明中的 textView 文字的色彩 </p>
 * <p> 赋值样例:#666666</p>
 * <p>39、lm_footer_textSize</p>
 * <p> 类型:int</p>
 * <p> 阐明:第三十七条阐明中的 textView 文字的大小 </p>
 * <p> 赋值样例:14</p>
 * <p>40、lm_footer_textStyle</p>
 * <p> 类型:Typeface</p>
 * <p> 阐明:第三十七条阐明中的 textView 文字的款式(失常,斜体、加粗)</p>
 * <p> 赋值样例:Typeface.defaultFromStyle(Typeface.NORMAL)</p>
 * <p>41、lm_footer_text_adjustMargins </p>
 * <p> 类型:Boolean(默认为 false)</p>
 * <p> 阐明:是否调整第三十七条阐明中的 textView 的边距 </p>
 * <p> 赋值样例:true</p>
 * <p>42、lm_footer_text_adjustMarginsLeft </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第三十七条阐明中的 textView 的右边距,如果 lm_footer_text_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(14)</p>
 * <p>43、lm_footer_text_adjustMarginsTop </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第三十七条阐明中的 textView 的上边距,如果 lm_footer_text_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(14)</p>
 * <p>44、lm_footer_text_adjustMarginsRight </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第三十七条阐明中的 textView 的左边距,如果 lm_footer_text_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(14)</p>
 * <p>45、lm_footer_text_adjustMarginsBottom </p>
 * <p> 类型:int(要求单位:px,因为须要把(dp/dip 值转换为 px 值))</p>
 * <p> 阐明:第三十七条阐明中的 textView 的下边距,如果 lm_footer_text_adjustMargins 为 false, 则此属性有效 </p>
 * <p> 赋值样例:ViewUtil.dpToPx(14)</p>
 * <br><br>
 * @author Jidcoo
 */
public abstract class ViewStyleConfigurator{
    /**
     * 下拉刷新控件色彩
     */
    public  String refreshViewColor;

    //*********// 回复加载更多控件款式 //*************//
    //Part1//
    public  String lmv_showText;
    public  int lmv_textSize;
    public  String lmv_textColor;
    public  Typeface lmv_textStyle;
    //Part2//
    public  String lmv_loading_showText;
    public  int lmv_loading_textSize;
    public  String lmv_loading_textColor;
    public  Typeface lmv_loading_textStyle;
    public  String lmv_loading_progressBarColor;
    public  int lmv_loading_progressBarSize;
    //Part3//
    public  boolean lmv_adjustMargins;
    public  int lmv_adjustMarginsLeft;//dp
    public  int lmv_adjustMarginsTop;//dp
    public  int lmv_adjustMarginsRight;//dp
    public  int lmv_adjustMarginsBottom;//dp
    //*********// 回复加载更多控件款式 //*************//

    //*********// 分割线总款式 //*************//
    public  String dividerColor;
    public  int dividerHeight;//dp
    //*********// 分割线总款式 //*************//

    //*********// 回复 Item 最初一项的下划线(分款式)//*************//
    public boolean isDrawChildDivider;
    public  boolean c_divider_adjustMargins;
    public  int c_divider_adjustMarginsLeft;//dp
    public  int c_divider_adjustMarginsTop;//dp
    public  int c_divider_adjustMarginsRight;//dp
    public  int c_divider_adjustMarginsBottom;//dp
    //*********// 回复 Item 最初一项的下划线(分款式)//*************//


    //*********// 评论 Item 的分割线(分款式)//*************//
    /**
     * 评论 Item 的分割线色彩、高度与回复 Item 的分割线一样
     */
    public boolean  f_divider_adjustMargins;
    public  int f_divider_adjustMarginsLeft;//dp
    public  int f_divider_adjustMarginsTop;//dp
    public  int f_divider_adjustMarginsRight;//dp
    public  int f_divider_adjustMarginsBottom;//dp
    //*********// 评论 Item 的分割线(分款式)//*************//

    //*********// 底部上拉加载更多圆形 ProgressBar 的大小和色彩 //*************//
    public int lm_footerProgressBarSize=12;//dp
    public String lm_footerProgressBarColor;
    public boolean  lm_footerProgressBar_adjustMargins;
    public  int lm_footerProgressBar_adjustMarginsLeft;//dp
    public  int lm_footerProgressBar_adjustMarginsTop;//dp
    public  int lm_footerProgressBar_adjustMarginsRight;//dp
    public  int lm_footerProgressBar_adjustMarginsBottom;//dp
    //*********// 底部上拉加载更多圆形 ProgressBar 的大小和色彩 //*************//


    //*********// 底部上拉加载更多实现后的 textView//*************//
    // 文本, 色彩、大小、款式、边距
    public String lm_footer_text;
    public String lm_footer_textColor;
    public int lm_footer_textSize=12;
    public Typeface lm_footer_textStyle;
    public boolean  lm_footer_text_adjustMargins;
    public  int lm_footer_text_adjustMarginsLeft;//dp
    public  int lm_footer_text_adjustMarginsTop;//dp
    public  int lm_footer_text_adjustMarginsRight;//dp
    public  int lm_footer_text_adjustMarginsBottom;//dp
    //*********// 底部上拉加载更多实现后的 textView//*************//
    
}

ViewStyleConfigurator 是款式配置器抽象类。该款式配置器针对 固有控件的款式 的具体配置。抽象类中的所有变量都是用来设置固有控件的款式。所有的款式变量的解释和阐明都有具体充沛的正文。在这就不一一阐明了。

在自定义款式的时候创立一个类继承自这个抽象类,而后对须要自定义的款式变量赋值就能够了。

例子:(这里贴出的是我的项目中的默认款式配置器,自定义款式配置器能够参照 defaults 包下的 DefaultViewStyleConfigurator 类)

/**
 * 默认款式配置器
 * <p> 此配置器为规范模板 </p>
 * <p> 自定义款式配置器必须继承自 ViewStyleConfigurator,查看{@link ViewStyleConfigurator}</p>
 * <p> 款式变量阐明,请查看{@link ViewStyleConfigurator}</p>
 * <p> 实际上,自定义款式配置器能够间接复制本类,而后再依据具体把款式批改就好了 </p>
 * @author Jidcoo
 */
public class DefaultViewStyleConfigurator extends ViewStyleConfigurator {public DefaultViewStyleConfigurator(Context context) {
        /**
         * 下拉刷新控件色彩
         */
        refreshViewColor = "#D81B60";
        //*********// 回复加载更多控件款式 //*************//
        //Part1//
        lmv_showText = "开展更多回复";
        lmv_textSize = 14;
        lmv_textColor = "#D81B60";
        lmv_textStyle = Typeface.defaultFromStyle(Typeface.NORMAL);
        //Part2//
        lmv_loading_showText = "加载中";
        lmv_loading_textSize = 14;
        lmv_loading_textColor = "#666666";
        lmv_loading_textStyle = Typeface.defaultFromStyle(Typeface.NORMAL);
        lmv_loading_progressBarColor = "#666666";
        lmv_loading_progressBarSize = ViewUtil.dpToPx(14, context);
        //Part3//
        lmv_adjustMargins = true;
        lmv_adjustMarginsLeft = ViewUtil.dpToPx(88, context);//dp
        lmv_adjustMarginsTop = ViewUtil.dpToPx(5, context);//dp
        lmv_adjustMarginsRight = 0;//dp
        lmv_adjustMarginsBottom = ViewUtil.dpToPx(5, context);//dp
        //*********// 回复加载更多控件款式 //*************//
        //*********// 分割线总款式 //*************//
        dividerColor = "#f0f0f0";
        dividerHeight = ViewUtil.dpToPx(1, context);//dp
        //*********// 分割线总款式 //*************//
        //*********// 回复 Item 最初一项的下划线 //*************//
        isDrawChildDivider = true;
        c_divider_adjustMargins = true;
        c_divider_adjustMarginsLeft = ViewUtil.dpToPx(88, context);//dp
        c_divider_adjustMarginsTop = ViewUtil.dpToPx(5, context);//dp
        c_divider_adjustMarginsRight = 0;//dp
        c_divider_adjustMarginsBottom = ViewUtil.dpToPx(5, context);//dp
        //*********// 回复 Item 最初一项的下划线 //*************//
        //*********// 评论 Item 的分割线 //*************//
        f_divider_adjustMargins = false;
        f_divider_adjustMarginsLeft = 0;//dp
        f_divider_adjustMarginsTop = 0;//dp
        f_divider_adjustMarginsRight = 0;//dp
        f_divider_adjustMarginsBottom = 0;//dp
        //*********// 评论 Item 的分割线 //*************//
        //*********// 底部上拉加载更多圆形 ProgressBar 的大小和色彩 //*************//
        lm_footerProgressBarSize = ViewUtil.dpToPx(20, context);//dp
        lm_footerProgressBarColor = "#c3c8cb";
        lm_footerProgressBar_adjustMargins = false;
        lm_footerProgressBar_adjustMarginsLeft = 0;//dp
        lm_footerProgressBar_adjustMarginsTop = 0;//dp
        lm_footerProgressBar_adjustMarginsRight = 0;//dp
        lm_footerProgressBar_adjustMarginsBottom = 0;//dp
        //*********// 底部上拉加载更多圆形 ProgressBar 的大小和色彩 //*************//


        //*********// 底部上拉加载更多实现后的 textView//*************//
        // 文本, 色彩、大小、款式、边距
        lm_footer_text = "评论都给你看完了哦~";
        lm_footer_textColor = "#c3c8cb";
        lm_footer_textSize = 14;
        lm_footer_textStyle = Typeface.defaultFromStyle(Typeface.NORMAL);
        lm_footer_text_adjustMargins = false;
        lm_footer_text_adjustMarginsLeft = 0;//dp
        lm_footer_text_adjustMarginsTop = 0;//dp
        lm_footer_text_adjustMarginsRight = 0;//dp
        lm_footer_text_adjustMarginsBottom = 0;//dp
        //*********// 底部上拉加载更多实现后的 textView//*************//
    }
}

2.5、总结

超长的篇幅解释阐明应用控件中须要用到的框架类,能够说是应用 CommentView 的实践局部。超长超啰嗦,然而这些阐明都是十分重要的,也是必须的。为什么这么说呢?因为 下面的这些框架类的阐明和例子都是在应用 CommentView 过程中业务层须要用到的 ,也就是说 了解了下面简明扼要的解释后,应用 CommentView 就非常简单了

所以只管非常啰嗦,然而有些货色须要特地阐明一下。以上都是实践局部(非常干燥、又长又臭……)有了上述这些对整个控件框架的整体理解,应用这个控件库就非常容易了

留神:我的项目是应用 AndroidX 库开发,局部控件是 AndroidX 库的控件,如果你的我的项目没有迁徙到 AndroidX 库开发,能够把 CommentView 控件库中的那些 AndroidX 库控件批改为你以后我的项目的 Android 库的控件就能够了。

上面就要讲 CommentView 理论应用局部了(了解了下面的实践,说实话应用没有任何技术含量)。

三、控件的应用

3.1、控件办法介绍

以下是控件对外颁布的所有业务办法。

办法 参数 阐明
.callbackBuilder() \ 获取 CallbackBuilder 实例设置须要的回调,无论是否设置回调,都必须调用.callbackBuilder().buildCallback()办法实现初始化。并且初始化必须在 loadComplete()调用之前实现。
.loadComplete() AbstractCommentModel 首次加载数据 时调用此办法,留神:设置回调,设置空数据视图、设置谬误视图、设置自定义款式配置器,设置头布局,这 5 个办法都必须要在 loadComplete()这个办法调用之前调用,否则这 5 个办法生效。
.loadFailed() boolean isShowErrorView 首次加载数据失败时调用,boolean 参数示意是否显示谬误视图。
.refreshComplete() AbstractCommentModel 刷新数据实现后调用,传入刷新后的数据实体类。该办法调用后 OnPullRefreshCallback 的 complete()办法会被调用。
.refreshFailed() String msg,boolean isShowErrorView 数据刷新失败时调用,msg 示意错误信息,boolean 参数示意是否显示谬误视图。该办法调用后 OnPullRefreshCallback 的 failure(String msg)办法会被调用。
.loadMoreComplete() AbstractCommentModel 加载更多评论数据实现后调用,传入一个数据实体类。该办法调用后 OnCommentLoadMoreCallback 的 complete()办法会被调用。
.loadMoreFailed() String msg,boolean isShowErrorView 加载更多评论数据失败时调用,msg 示意错误信息,boolean 参数示意是否显示谬误视图。该办法调用后 OnCommentLoadMoreCallback 的 failure(String msg)办法会被调用。
.loadMoreReplyComplete() AbstractCommentModel 加载更多回复数据实现后调用,传入一个数据实体类。该办法调用后 OnReplyLoadMoreCallback 的 complete()办法会被调用。
.loadMoreReplyFailed() String msg,boolean isShowErrorView 加载更多评论数据失败时调用,msg 示意错误信息,boolean 参数示意是否显示谬误视图。该办法调用后 OnReplyLoadMoreCallback 的 failure(String msg)办法会被调用。
.getCommentList() \ 获取所有评论数据返回 List
.getReplyList() int position 依据 position 所在的评论获取所在评论的所有回复数据返回 List
.addComment() C<?extend CommentEnable> comment 增加一条评论数据到以后的评论数据汇合中
.addReply() R<?extend ReplyEnable> comment,int position 增加一条回复数据到 position 所在的评论的回复数据汇合中
.setEmptyView() View view 为控件设置空数据视图,留神:此办法必须在 loadComplete()办法调用前调用,也就是说要在首次加载数据前调用,否则此办法有效。
.setErrorView() View view 为控件设置谬误视图,留神:此办法必须在 loadComplete()办法调用前调用,也就是说要在首次加载数据前调用,否则此办法有效。
.addHeaderView() View view,boolean canClickable 为控件增加头视图,并且设置该视图是否响应点击事件。留神:此办法倡议在 loadComplete()办法调用前调用。
.removeHeaderView() View view 移除以后控件的对应的头视图
.setViewStyleConfigurator() ViewStyleConfigurator 设置自定义的款式配置器,留神:此办法必须在 loadComplete()办法调用前调用,也就是说要在首次加载数据前调用,否则此办法有效。

3.2、根本应用

第一步:引入控件库:

有两种办法:

1、近程仓库

在 module 的 build.gradle 中增加 jcenter 仓库:

buildscript {
    repositories {jcenter()
    }
}

而后在 dependencies 模块中增加依赖即可:

implementation 'com.jidcoo.android.widget.commentview:CommentView:1.0.0'

2、本地仓库

把源码包下载下来,把 commentview 库放在与以后 module 的同级。

而后在 dependencies 模块中增加本地依赖即可:

implementation project(path: ':commentview')

第二步:引入控件:

控件的引入办法有两种:

1、XML 布局文件中引入

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:id="@+id/container"
    android:layout_height="match_parent">


  <com.jidcoo.android.widget.commentview.CommentView
      android:id="@+id/commentView"
      android:layout_width="match_parent"
      android:layout_height="match_parent"/>
</LinearLayout>

而后在 Activity 中实例化控件。

2、Java 代码中动态创建

// 控件容器
LinearLayout mContainer;
CommentView commentView=new CommentView(this,mContainer);

CommentView 的构造方法:
public CommentView(Context context, ViewGroup attachTo)

第一个参数是 Activity 的上下文。第二个参数是 ViewGroup,也就是 将控件挂靠在这个指定的布局上 。留神: 当 attachTo 参数为空时,须要手动把控件增加到布局中,否则控件将不会显示

第三步:初始化控件:

设置自定义款式配置器

如果应用默认款式的话就不须要调用这个办法,如果应用自定义款式配置器时调用该办法必须在 loadComplete()调用前调用,否则该办法有效。

commentView.setViewStyleConfigurator(你的款式配置器);

设置空数据视图
如果不须要设置空数据视图就不须要调用这个办法,如果须要设置空数据视图时调用该办法必须在 loadComplete()调用前调用,否则该办法有效。

commentView.setEmptyView(你的空数据视图);

设置谬误视图
如果不须要设置谬误视图就不须要调用这个办法,如果须要设置谬误视图时调用该办法必须在 loadComplete()调用前调用,否则该办法有效。

commentView.setErrorView(你的谬误视图);

增加控件头视图
如果不须要增加控件头视图就不须要调用这个办法,如果须要增加控件头视图时调用该办法倡议在 loadComplete()调用前调用。

commentView.addHeaderView(你的谬误视图,是否响应点击事件);

第四步:初始化回调(十分重要,必须初始化):

无论是否须要设置回调,都要调用.buildCallback()办法实现初始化。

并且初始化回调的工作必须要在 loadComplete()办法调用之前(即首次加载数据之前)实现,否则控件将无奈失常应用。

反对的回调:
1、CustomCommentItemCallback:自定义评论布局回调
2、CustomReplyItemCallback:自定义回复布局回调
3、OnPullRefreshCallback:上拉刷新回调
4、OnCommentLoadMoreCallback:下拉加载更多评论回调
5、OnReplyLoadMoreCallback:加载更多回复回调
6、OnItemClickCallback:Item 的点击事件回调
7、OnScrollCallback:控件滚动事件回调

当须要设置回调时:

设置完回调后必须调用.buildCallback()办法,否则回调不会失效,控件也无奈失常应用。

commentView.callbackBuilder()
           .setOnPullRefreshCallback(你的回调实例)
           .onItemClickCallback(你的回调实例)
           ...... 设置更多回调
           ...... 设置更多回调
           // 设置实现后必须调用 CallbackBuilder 的 buildCallback()办法,否则设置的回调有效,控件也无奈失常显示。// 无论是否设置回调,buildCallback()办法都必须调用。.buildCallback();

当不须要设置回调时:

必须调用.buildCallback()办法,否则控件也无奈失常应用。

commentView.callbackBuilder().buildCallback();

第五步:设置数据:

当所有的初始化工作都实现后,就能够申请后盾返回评论数据或加载本地数据为控件设置数据了。实现设置数据后,控件就能正确显示评论数据了。

commentView.loadComplete(你的数据模型实体类);

3.3、具体实例(自定义仿微信公众号文章评论)

布局文件:custom_use.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 
    android:layout_width="match_parent"
    android:background="#f0f0f0"
    android:layout_height="match_parent">


  <com.jidcoo.android.widget.commentview.CommentView
      android:id="@+id/commentView"
      android:layout_width="match_parent"
      android:layout_height="match_parent"/>
</LinearLayout>

自定义评论布局:custom_item_comment.xml

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

    <com.jidcoo.android.widgettest.custom.SampleCircleImageView
        android:id="@+id/ico"
        android:layout_width="28dp"
        android:layout_height="28dp"
        android:layout_marginLeft="14dp"
        android:layout_marginTop="18dp"
        app:radius="2dp"
        app:src="@drawable/teaser" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:layout_marginRight="14dp"
        android:layout_marginBottom="4dp">


        <TextView
            android:id="@+id/user"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="8dp"
            android:textColor="#666666"
            android:textSize="13sp" />

        <ImageView
            android:id="@+id/comment_item_like"
            android:layout_width="18dp"
            android:layout_height="18dp"
            android:layout_alignParentRight="true"
            android:layout_marginRight="30dp"
            android:padding="3dp"
            android:src="@drawable/pxjh"
            android:visibility="visible" />

        <TextView
            android:id="@+id/prizes"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:textColor="#666666"
            android:textSize="13sp" />

        <TextView
            android:id="@+id/data"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="8dp"
            android:layout_marginTop="18dp"
            android:textColor="#1C1C1C" />
    </RelativeLayout>


</LinearLayout>

自定义回复布局:custom_item_reply.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:id="@+id/reply_rootView"
    android:layout_height="wrap_content"
    android:orientation="vertical">

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <View
        android:id="@+id/line"
        android:layout_width="2dp"
        android:layout_height="wrap_content"
        android:layout_alignTop="@id/right"
        android:layout_alignBottom="@id/right"
        android:layout_marginLeft="52dp"
        android:layout_marginTop="2dp"
        android:layout_marginBottom="2dp"
        android:background="#c3c8cb" />


    <RelativeLayout
        android:id="@+id/right"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginRight="14dp"
        android:layout_marginBottom="4dp"
        android:layout_toRightOf="@id/line">


        <TextView
            android:id="@+id/user"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="6dp"
            android:textColor="#666666"
            android:textSize="13sp" />

        <ImageView
            android:id="@+id/comment_item_like"
            android:layout_width="18dp"
            android:layout_height="18dp"
            android:layout_alignParentRight="true"
            android:layout_marginRight="30dp"
            android:padding="3dp"
            android:src="@drawable/pxjh"
            android:visibility="visible" />

        <TextView
            android:id="@+id/prizes"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:textColor="#666666"
            android:textSize="13sp" />

        <TextView
            android:id="@+id/data"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="6dp"
            android:layout_marginTop="18dp"
            android:textColor="#1C1C1C" />
    </RelativeLayout>


</RelativeLayout>
</LinearLayout>

自定义数据模型:CustomCommentModel.java

import com.jidcoo.android.widget.commentview.model.AbstractCommentModel;
import com.jidcoo.android.widget.commentview.model.CommentEnable;
import com.jidcoo.android.widget.commentview.model.ReplyEnable;

import java.util.List;

public class CustomCommentModel extends AbstractCommentModel<CustomCommentModel.CustomComment> {
    public List<CustomComment> comments;

    @Override
    public List<CustomComment> getComments() {return comments;}

    public class CustomComment extends CommentEnable{
        public List<CustomReply> replies;
        public String posterName;
        public String data;

        public CustomComment() {}
        
        public void setReplies(List<CustomReply> replies) {this.replies = replies;}

        public String getPosterName() {return posterName;}

        public void setPosterName(String posterName) {this.posterName = posterName;}

        public String getData() {return data;}

        public void setData(String data) {this.data = data;}
        
        @Override
        public  List<CustomReply> getReplies() {return replies;}

        public class CustomReply extends ReplyEnable{
            public String replierName;
            public String data;

            public CustomReply() {}
            public String getReplierName() {return replierName;}

            public void setReplierName(String replierName) {this.replierName = replierName;}

            public String getData() {return data;}

            public void setData(String data) {this.data = data;}
        }
    }
}

评论布局 ViewHolder:CustomCommentViewHolder.java

import android.view.View;
import android.widget.TextView;
import com.jidcoo.android.widgettest.R;

public class CustomCommentViewHolder {
      public TextView userName,prizes,comment;
      public SampleCircleImageView ico;

    public CustomCommentViewHolder(View view) {userName=view.findViewById(R.id.user);
        prizes=view.findViewById(R.id.prizes);
        comment=view.findViewById(R.id.data);
       ico=view.findViewById(R.id.ico);
    }
}

回复布局 ViewHolder:CustomReplyViewHolder.java

import android.view.View;
import android.widget.TextView;
import com.jidcoo.android.widget.commentview.view.ViewHolder;
import com.jidcoo.android.widgettest.R;

public class CustomReplyViewHolder extends ViewHolder {
    public TextView userName,prizes,reply;

    public CustomReplyViewHolder(View view) {super(view);
        userName=view.findViewById(R.id.user);
        prizes=view.findViewById(R.id.prizes);
        reply=view.findViewById(R.id.data);
    }
}

自定义款式配置器:CustomViewStyleConfigurator.java

import android.content.Context;
import android.graphics.Typeface;
import com.jidcoo.android.widget.commentview.utils.ViewUtil;
import com.jidcoo.android.widget.commentview.view.ViewStyleConfigurator;


public class CustomViewStyleConfigurator extends ViewStyleConfigurator {public CustomViewStyleConfigurator(Context context) {
        /**
         * 下拉刷新控件色彩
         */
        refreshViewColor = "#D81B60";
        //*********// 回复加载更多控件款式 //*************//
        //Part1//
        lmv_showText = "开展更多回复";
        lmv_textSize = 14;
        lmv_textColor = "#D81B60";
        lmv_textStyle = Typeface.defaultFromStyle(Typeface.NORMAL);
        //Part2//
        lmv_loading_showText = "加载中";
        lmv_loading_textSize = 14;
        lmv_loading_textColor = "#666666";
        lmv_loading_textStyle = Typeface.defaultFromStyle(Typeface.NORMAL);
        lmv_loading_progressBarColor = "#666666";
        lmv_loading_progressBarSize = ViewUtil.dpToPx(14, context);
        //Part3//
        lmv_adjustMargins = true;
        lmv_adjustMarginsLeft = ViewUtil.dpToPx(52, context);//dp
        lmv_adjustMarginsTop = ViewUtil.dpToPx(5, context);//dp
        lmv_adjustMarginsRight = 0;//dp
        lmv_adjustMarginsBottom = ViewUtil.dpToPx(5, context);//dp
        //*********// 回复加载更多控件款式 //*************//
        //*********// 分割线总款式 //*************//
        dividerColor = "#00000000";
        dividerHeight = ViewUtil.dpToPx(1, context);//dp
        //*********// 分割线总款式 //*************//
        //*********// 回复 Item 最初一项的下划线 //*************//
//        isDrawChildDivider = false;
//        c_divider_adjustMargins = true;
//        c_divider_adjustMarginsLeft = ViewUtil.dpToPx(88, context);//dp
//        c_divider_adjustMarginsTop = ViewUtil.dpToPx(5, context);//dp
//        c_divider_adjustMarginsRight = 0;//dp
//        c_divider_adjustMarginsBottom = ViewUtil.dpToPx(5, context);//dp
//        //*********// 回复 Item 最初一项的下划线 //*************//
//        //*********// 评论 Item 的分割线 //*************//
//        f_divider_adjustMargins = false;
//        f_divider_adjustMarginsLeft = 0;//dp
//        f_divider_adjustMarginsTop = 0;//dp
//        f_divider_adjustMarginsRight = 0;//dp
//        f_divider_adjustMarginsBottom = 0;//dp
        //*********// 评论 Item 的分割线 //*************//
        //*********// 底部上拉加载更多圆形 ProgressBar 的大小和色彩 //*************//
        lm_footerProgressBarSize = ViewUtil.dpToPx(20, context);//dp
        lm_footerProgressBarColor = "#666666";
        lm_footerProgressBar_adjustMargins = false;
        lm_footerProgressBar_adjustMarginsLeft = 0;//dp
        lm_footerProgressBar_adjustMarginsTop = 0;//dp
        lm_footerProgressBar_adjustMarginsRight = 0;//dp
        lm_footerProgressBar_adjustMarginsBottom = 0;//dp
        //*********// 底部上拉加载更多圆形 ProgressBar 的大小和色彩 //*************//


        //*********// 底部上拉加载更多实现后的 textView//*************//
        // 文本, 色彩、大小、款式、边距
        lm_footer_text = "到底了(⊙o⊙)!";
        lm_footer_textColor = "#c3c8cb";
        lm_footer_textSize = 14;
        lm_footer_textStyle = Typeface.defaultFromStyle(Typeface.NORMAL);
        lm_footer_text_adjustMargins = false;
        lm_footer_text_adjustMarginsLeft = 0;//dp
        lm_footer_text_adjustMarginsTop = 0;//dp
        lm_footer_text_adjustMarginsRight = 0;//dp
        lm_footer_text_adjustMarginsBottom = 0;//dp
        //*********// 底部上拉加载更多实现后的 textView//*************//
    }
}

Avtivity:CustomUseInLocalActivity.java

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.google.gson.Gson;
import com.jidcoo.android.widget.commentview.CommentView;
import com.jidcoo.android.widget.commentview.callback.CustomCommentItemCallback;
import com.jidcoo.android.widget.commentview.callback.CustomReplyItemCallback;
import com.jidcoo.android.widget.commentview.callback.OnCommentLoadMoreCallback;
import com.jidcoo.android.widget.commentview.callback.OnItemClickCallback;
import com.jidcoo.android.widget.commentview.callback.OnPullRefreshCallback;
import com.jidcoo.android.widget.commentview.callback.OnReplyLoadMoreCallback;
import com.jidcoo.android.widgettest.R;
import com.jidcoo.android.widgettest.simple.LocalServer;
import java.lang.ref.WeakReference;

/**
 * 对于 CommentView 的自定义数据类型和布局的应用实例(应用本地测试数据)* 应用自定义款式配置器,自定义数据模型,自定义布局
 * <u> 留神:应用自定义数据类型就必须自定义布局实现,否则会抛出数据模型的 java.lang.ClassCastException 异样 </u><br></br>
 * @author Jidcoo
 */
public class CustomUseInLocalActivity extends AppCompatActivity {
    private CommentView commentView;
    private Gson gson;
    private LocalServer localServer;

    //
    private static class ActivityHandler extends Handler {
        private final WeakReference<CustomUseInLocalActivity> mActivity;
        public ActivityHandler(CustomUseInLocalActivity activity) {mActivity = new WeakReference<CustomUseInLocalActivity>(activity);
        }
        @Override
        public void handleMessage(Message msg) {CustomUseInLocalActivity activity = mActivity.get();
            if (activity != null) {switch (msg.what){
                    case 1:
                        //commentView.loadFailed(true);// 理论网络申请中如果加载失败调用此办法
                        activity.commentView.loadComplete(activity.gson.fromJson((String)msg.obj,CustomCommentModel.class));
                        break;
                    case 2:
                        //commentView.refreshFailed();// 理论网络申请中如果加载失败调用此办法
                        activity.commentView.refreshComplete(activity.gson.fromJson((String)msg.obj, CustomCommentModel.class));
                        break;
                    case 3:
                        //commentView.loadFailed();// 理论网络申请中如果加载失败调用此办法
                        activity.commentView.loadMoreComplete(activity.gson.fromJson((String)msg.obj,CustomCommentModel.class));
                        break;
                    case 4:
                        //commentView.loadMoreReplyFailed();// 理论网络申请中如果加载失败调用此办法
                        activity.commentView.loadMoreReplyComplete(activity.gson.fromJson((String)msg.obj,CustomCommentModel.class));
                        break;
                }
            }
        }
    }
    private final ActivityHandler activityHandler = new ActivityHandler(this);
    //

     @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);
        setContentView(R.layout.custom_use);
        gson=new Gson();
        localServer=new LocalServer(this,"api2");
        commentView=findViewById(R.id.commentView);
         // 设置空视图
         //commentView.setEmptyView(view);
         // 设置谬误视图
         //commentView.setErrorView(view);
         // 增加控件头布局
        // commentView.addHeaderView();
        commentView.setViewStyleConfigurator(new CustomViewStyleConfigurator(this));

        commentView.callbackBuilder()
                // 自定义评论布局(必须应用 ViewHolder 机制)--CustomCommentItemCallback<C> 泛型 C 为自定义评论数据类
                .customCommentItem(new CustomCommentItemCallback<CustomCommentModel.CustomComment>() {
                    @Override
                    public View buildCommentItem(int groupPosition, CustomCommentModel.CustomComment comment, LayoutInflater inflater, View convertView, ViewGroup parent) {// 应用办法就像 adapter 外面的 getView()办法一样
                        final CustomCommentViewHolder holder;
                        if(convertView==null){
                            // 应用自定义布局
                            convertView=inflater.inflate(R.layout.custom_item_comment,parent,false);
                            holder=new CustomCommentViewHolder(convertView);
                            // 必须应用 ViewHolder 机制
                            convertView.setTag(holder);
                        }else {holder= (CustomCommentViewHolder) convertView.getTag();}
                        holder.prizes.setText("100");
                        holder.userName.setText(comment.getPosterName());
                        holder.comment.setText(comment.getData());
                        return convertView;
                    }
                })
                // 自定义评论布局(必须应用 ViewHolder 机制)// 并且自定义 ViewHolder 类必须继承自 com.jidcoo.android.widget.commentview.view.ViewHolder
                // --CustomReplyItemCallback<R> 泛型 R 为自定义回复数据类
                .customReplyItem(new CustomReplyItemCallback<CustomCommentModel.CustomComment.CustomReply>() {
                    @Override
                    public View buildReplyItem(int groupPosition, int childPosition, boolean isLastReply, CustomCommentModel.CustomComment.CustomReply reply, LayoutInflater inflater, View convertView, ViewGroup parent) {// 应用办法就像 adapter 外面的 getView()办法一样
                        // 此类必须继承自 com.jidcoo.android.widget.commentview.view.ViewHolder,否则报错
                        CustomReplyViewHolder holder=null;
                        // 此类必须继承自 com.jidcoo.android.widget.commentview.view.ViewHolder,否则报错
                        if(convertView==null){
                            // 应用自定义布局
                            convertView=inflater.inflate(R.layout.custom_item_reply,parent,false);
                            holder=new CustomReplyViewHolder(convertView);
                            // 必须应用 ViewHolder 机制
                            convertView.setTag(holder);
                        }else {holder= (CustomReplyViewHolder) convertView.getTag();}
                        holder.userName.setText(reply.getReplierName());
                        holder.reply.setText(reply.getData());
                        holder.prizes.setText("100");
                        return convertView;
                    }
                })
                // 下拉刷新回调
                .setOnPullRefreshCallback(new MyOnPullRefreshCallback())
                // 评论、回复 Item 的点击回调(点击事件回调).setOnItemClickCallback(new MyOnItemClickCallback())
                // 回复数据加载更多回调(加载更多回复).setOnReplyLoadMoreCallback(new MyOnReplyLoadMoreCallback())
                // 上拉加载更多回调(加载更多评论数据).setOnCommentLoadMoreCallback(new MyOnCommentLoadMoreCallback())
                // 设置实现后必须调用 CallbackBuilder 的 buildCallback()办法,否则设置的回调有效
                .buildCallback();
         load(1,1);
    }


    private void load(int code,int handlerId){localServer.get(code,activityHandler,handlerId);
    }


    /**
     * 下拉刷新回调类
     */
    class MyOnPullRefreshCallback implements OnPullRefreshCallback {

        @Override
        public void refreshing() {load(1,2);


        }

        @Override
        public void complete() {// 加载实现后的操作}

        @Override
        public void failure(String msg) {}}




    /**
     * 上拉加载更多回调类
     */
    class MyOnCommentLoadMoreCallback implements OnCommentLoadMoreCallback {

        @Override
        public void loading(int currentPage, int willLoadPage, boolean isLoadedAllPages) {
            // 因为测试数据写死了,所以这里的逻辑也是写死的
            if (!isLoadedAllPages){if(willLoadPage==2){load(2,3);
                }else if(willLoadPage==3){load(3,3);
                }
            }
        }

        @Override
        public void complete() {// 加载实现后的操作}

        @Override
        public void failure(String msg) {}}

    /**
     * 回复加载更多回调类
     */
    class MyOnReplyLoadMoreCallback implements OnReplyLoadMoreCallback<CustomCommentModel.CustomComment.CustomReply> {


        @Override
        public void loading(CustomCommentModel.CustomComment.CustomReply reply, int willLoadPage) {if(willLoadPage==2){load(5,4);
                }else if(willLoadPage==3){load(6,4);
            }
        }

        @Override
        public void complete() {}

        @Override
        public void failure(String msg) {}}

    /**
     * 点击事件回调
     */
    class MyOnItemClickCallback implements OnItemClickCallback<CustomCommentModel.CustomComment, CustomCommentModel.CustomComment.CustomReply> {


        @Override
        public void commentItemOnClick(int position, CustomCommentModel.CustomComment comment, View view) {Toast.makeText(CustomUseInLocalActivity.this,"你点击的评论:"+comment.getData(),Toast.LENGTH_SHORT).show();}

        @Override
        public void replyItemOnClick(int c_position, int r_position, CustomCommentModel.CustomComment.CustomReply reply, View view) {Toast.makeText(CustomUseInLocalActivity.this,"你点击的回复:"+reply.getData(),Toast.LENGTH_SHORT).show();}
    }

}

3.4、总结

以上就是控件的应用办法和具体应用例子,更多用法能够查看测试利用的源码中的例子。到这里,文章就差不多要结尾了。

四、后话

哈哈,有人可能会问为什么要做这个控件呀?

因为前一段时间做我的项目的时候须要开发文章的评论性能,而后须要用到相似的控件,原本想在网上找找有没有开源的,然而全网搜遍当前没有发现适合的。所以就本人手动写了一个。

然而我用在我的项目中的是这个开源的 CommentView 再进行深度优化和深度定制过的。也就是说目前这个开源进去的版本其实是比拟通用适配版本的,能够优化的中央还有很多很多很多。同时也存在不少 BUG。还有那个测试用例 WidgetTest 也有很多能够优化的中央,只是当初没有太多工夫去专门做优化,有空我会再去优化。大家有趣味的能够一起到 github 优化这个控件,也能够提出对这个控件的一些问题、想法以及可优化的点。哈哈,欢送大家一起来把这个开源控件库做的更好更弱小。

前面有工夫的话,这个开源控件库的安顿:
1、优化
2、优化
3、扩充自定义开发的范畴
4、联合市面上的 APP 评论模块开发更多通用的款式框架
5、增加更多功能(嵌套滑动等等更多实用功能)
6、更多的往架构为一个轮子倒退,成为可能适配绝大多数需要的控件库
……
……
6、优化

有趣味、有工夫的能够一起退出这个我的项目的欠缺,十分欢送大家呀!!

顺便提一下,目前用在我工作的我的项目中的版本显示 10000+ 的数据性能都挺高的,在大数据量时内存开销也稳固在一个绝对的值。毕竟是在这个开源版本根底上做了很多的深度优化。所以说,所以说,如果应用的场景是数据量比拟大的状况下,优化是很有必要的哦,不然数据量比拟大很容易 OOM。

五、对于作者

我叫 Jidcoo,一名理工男,一个专一于 Java 后端同时又酷爱 Android 开发的花心大萝卜。我酷爱浏览、酷爱算法、酷爱分享……喜爱交换、喜爱团队单干。

有任何无关这个我的项目或者有任何其余问题、想法,都能够 POST 我:

我的邮箱:jidcoo@163.com

我的 GitHub: https://github.com/Jidcoo/

退出移动版