TouTiao开源项目 分析笔记16 新闻评论
1.要达到的效果
1.1.主要效果图
点击了标题栏的消息图标后,然后会跳转到评论详情的页面。
1.2.触发的点击事件
在新闻详情的片段中的菜单点击事件中
设置上方标题栏的消息标的监听事件
case R.id.action_open_comment:
NewsCommentActivity.launch(bean.getGroup_id() + "", bean.getItem_id() + "");
break;
bean就是某一个新闻的一些属性,从最前面item中传递过来的。
2.新闻评论详情活动
2.1.源代码
class NewsCommentActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.container)
val intent = intent
supportFragmentManager.beginTransaction()
.replace(R.id.container,
NewsCommentFragment.newInstance(intent.getStringExtra(ARG_GROUPID), intent.getStringExtra(ARG_ITEMID)))
.commit()
} companion object { private val TAG = "NewsCommentActivity"
private val ARG_GROUPID = "groupId"
private val ARG_ITEMID = "itemId" fun launch(groupId: String, itemId: String) {
InitApp.AppContext.startActivity(Intent(InitApp.AppContext, NewsCommentActivity::class.java)
.putExtra(ARG_GROUPID, groupId)
.putExtra(ARG_ITEMID, itemId)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
}
}
}
2.2.外部启动这个评论活动的一个静态launch函数。
这里需要将两个关键的参数保存起来,之后在评论中会用到。
2.3.然后是一个onCreate函数,这个活动优先执行。
将container替换成片段的布局。
2.4.在清单中配置这个活动
<activity
android:name=".module.news.comment.NewsCommentActivity"
android:configChanges="orientation|screenSize|uiMode"
android:label="@string/title_comment"
android:theme="@style/AppTheme.NoActionBar.Slidable"/>
3.新闻评论的片段
3.1.底层接口==>INewsComment
public interface INewsComment { interface View extends IBaseListView<Presenter> { /**
* 请求数据
*/
void onLoadData();
} interface Presenter extends IBasePresenter { /**
* 请求数据
*/
void doLoadData(String... groupId_ItemId); /**
* 再起请求数据
*/
void doLoadMoreData(); /**
* 设置适配器
*/
void doSetAdapter(List<NewsCommentBean.DataBean.CommentBean> list); /**
* 加载完毕
*/
void doShowNoMore();
}
}
3.2.新闻评论片段源代码
public class NewsCommentFragment extends BaseListFragment<INewsComment.Presenter> implements INewsComment.View{
private static final String GROUP_ID = "groupId";
private static final String ITEM_ID = "itemId";
private static final String TAG = "NewsCommentFragment";
private String groupId;
private String itemId; public static NewsCommentFragment newInstance(String groupId, String itemId) {
NewsCommentFragment instance = new NewsCommentFragment();
Bundle bundle = new Bundle();
bundle.putString(GROUP_ID, groupId);
bundle.putString(ITEM_ID, itemId);
instance.setArguments(bundle);
return instance;
} @Override
protected int attachLayoutId() {
return R.layout.fragment_list_toolbar;
} @Override
protected void initData() {
Bundle arguments = getArguments();
groupId = arguments.getString(GROUP_ID);
itemId = arguments.getString(ITEM_ID);
onLoadData();
} @Override
public void onLoadData() {
onShowLoading();
presenter.doLoadData(groupId, itemId);
} @Override
public void onRefresh() {
presenter.doRefresh();
} @Override
protected void initView(View view) {
super.initView(view);
Toolbar toolbar = view.findViewById(R.id.toolbar);
initToolBar(toolbar, true, getString(R.string.title_comment));
toolbar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
recyclerView.smoothScrollToPosition(0);
}
});
toolbar.setBackgroundColor(SettingUtil.getInstance().getColor()); adapter = new MultiTypeAdapter(oldItems);
Register.registerNewsCommentItem(adapter);
recyclerView.setAdapter(adapter);
recyclerView.addOnScrollListener(new OnLoadMoreListener() {
@Override
public void onLoadMore() {
if (canLoadMore) {
canLoadMore = false;
presenter.doLoadMoreData();
}
}
});
setHasOptionsMenu(true);
} @Override
public void onSetAdapter(final List<?> list) {
Items newItems = new Items(list);
newItems.add(new LoadingBean());
DiffCallback.notifyDataSetChanged(oldItems, newItems, DiffCallback.NEWS_COMMENT, adapter);
oldItems.clear();
oldItems.addAll(newItems);
canLoadMore = true;
} @Override
public void setPresenter(INewsComment.Presenter presenter) {
if (null == presenter) {
this.presenter = new NewsCommentPresenter(this);
}
} @Override
public void fetchData() { }
}
3.3.新建一个实例,供外部调用。
传进来两个参数,一个groupId,一个itemId。
传出去一个片段Fragment。
3.4.重写返回片段的布局==>fragment_list_toolbar.xml。
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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="match_parent"
android:background="@color/windowBackground"
android:fitsSystemWindows="true"
android:orientation="vertical"> <include layout="@layout/toolbar"/> <android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"> <android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadeScrollbars="true"
android:scrollbarFadeDuration="1"
android:scrollbars="vertical"
app:layoutManager="LinearLayoutManager">
</android.support.v7.widget.RecyclerView> </android.support.v4.widget.SwipeRefreshLayout> </android.support.design.widget.CoordinatorLayout>
预览页面:
3.5.初始化视图initView。
传进去一个view。
获取toolbar+点击事件。
新建一个adapter,给recycleView设置适配器+滑动监听事件。
设置菜单。
3.6.初始化数据initData。
获取存放在bundle中的两个信息。
然后调用处理器来加载数据。
3.7.重写onRefresh函数。
调用处理器的刷新。
3.8.重写加载函数onLoadData。
显示视图的加载圈。
然后调用处理器的加载数据函数。
3.9.重写设置适配器。
传入一个List。
比较新老数据,动态变化数据。
3.10.重写设置处理器。
传入一个底层接口中定义的一个处理器。
将这个处理器保存起来以后用。
3.11.重写填充数据的fetchData。
里面是空的。这里不做任何事情。
4.新闻评论的处理器
4.1.源代码
package com.jasonjan.headnews.module.news.comment; import com.jasonjan.headnews.api.IMobileNewsApi;
import com.jasonjan.headnews.bean.news.NewsCommentBean;
import com.jasonjan.headnews.main.ErrorAction;
import com.jasonjan.headnews.main.RetrofitFactory; import java.util.ArrayList;
import java.util.List; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers; /**
* Created by JasonJan on 2018/1/9.
*/ public class NewsCommentPresenter implements INewsComment.Presenter{
private static final String TAG = "NewsCommentPresenter";
private INewsComment.View view;
private String groupId;
private String itemId;
private int offset = 0;
private List<NewsCommentBean.DataBean.CommentBean> commentsBeanList = new ArrayList<>(); public NewsCommentPresenter(INewsComment.View view) {
this.view = view;
} @Override
public void doLoadData(String... groupId_ItemId){
try {
if (null == this.groupId) {
this.groupId = groupId_ItemId[0];
}
if (null == this.itemId) {
this.itemId = groupId_ItemId[1];
}
} catch (Exception e) {
ErrorAction.print(e);
} RetrofitFactory.getRetrofit().create(IMobileNewsApi.class)
.getNewsComment(groupId, offset)
.subscribeOn(Schedulers.io())
.map(new Function<NewsCommentBean, List<NewsCommentBean.DataBean.CommentBean>>() {
@Override
public List<NewsCommentBean.DataBean.CommentBean> apply(@NonNull NewsCommentBean newsCommentBean) throws Exception {
List<NewsCommentBean.DataBean.CommentBean> data = new ArrayList<>();
for (NewsCommentBean.DataBean bean : newsCommentBean.getData()) {
data.add(bean.getComment());
}
return data;
}
})
.compose(view.<List<NewsCommentBean.DataBean.CommentBean>>bindToLife())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<NewsCommentBean.DataBean.CommentBean>>() {
@Override
public void accept(@NonNull List<NewsCommentBean.DataBean.CommentBean> list) throws Exception {
if (null != list && list.size() > 0) {
doSetAdapter(list);
} else {
doShowNoMore();
}
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
doShowNetError();
ErrorAction.print(throwable);
}
});
} @Override
public void doLoadMoreData() {
offset += 20;
doLoadData();
} @Override
public void doSetAdapter(List<NewsCommentBean.DataBean.CommentBean> list) {
commentsBeanList.addAll(list);
view.onSetAdapter(commentsBeanList);
view.onHideLoading();
} @Override
public void doRefresh() {
if (commentsBeanList.size() != 0) {
commentsBeanList.clear();
offset = 0;
}
doLoadData();
} @Override
public void doShowNetError() {
view.onHideLoading();
view.onShowNetError();
} @Override
public void doShowNoMore() {
view.onHideLoading();
view.onShowNoMore();
}
}
4.2.一个构造函数。
传进去一个底层接口中定义的一个View。
保存这个View,以后再用。
4.3.重写doLoadData函数。
传进去一个String...类型,类似于数组。
然后调用API请求。
4.4.重写加载更多doLoadMoreData函数。
偏移量增加20即可。
然后再调用doLoadData函数。
4.5.重写设置适配器doSetAdapter函数。
传进去一个List。
然后调用视图层的onSetAdapter函数。
然后调用试图层的onHideLoading函数。
4.6.重写刷新。
将List清空,设置偏移量为0。
然后调用doLoadData。
4.7.重写网络错误。
调用视图层的隐藏加载函数。
调用视图层的显示网络错误。
4.8.重写没有更多。
调用视图层的隐藏加载函数。
调用视图层的显示没有更多函数。
5.注册数据类型
5.1.首先在新闻评论片段中给适配器添加数据类型
adapter = new MultiTypeAdapter(oldItems);
Register.registerNewsCommentItem(adapter);
recyclerView.setAdapter(adapter);
5.2.然后在自定义类Register统一注册这个页面需要的类型
public static void registerNewsCommentItem(@NonNull MultiTypeAdapter adapter) {
adapter.register(NewsCommentBean.DataBean.CommentBean.class, new NewsCommentViewBinder());
adapter.register(LoadingBean.class, new LoadingViewBinder());
adapter.register(LoadingEndBean.class, new LoadingEndViewBinder());
}
5.3.然后看一下这个新闻评论的视图绑定类==>NewsCommentViewBinder
package com.jasonjan.headnews.binder.news; import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView; import com.jasonjan.headnews.R;
import com.jasonjan.headnews.bean.news.NewsCommentBean;
import com.jasonjan.headnews.main.ErrorAction;
import com.jasonjan.headnews.main.IntentAction;
import com.jasonjan.headnews.module.base.BaseActivity;
import com.jasonjan.headnews.util.ImageLoader;
import com.jasonjan.headnews.widget.BottomSheetDialogFixed; import me.drakeet.multitype.ItemViewBinder; /**
* Created by JasonJan on 2018/1/9.
*/ public class NewsCommentViewBinder extends ItemViewBinder<NewsCommentBean.DataBean.CommentBean,NewsCommentViewBinder.ViewHolder> { @NonNull
@Override
protected NewsCommentViewBinder.ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
View view = inflater.inflate(R.layout.item_news_comment, parent, false);
return new ViewHolder(view);
} @Override
protected void onBindViewHolder(@NonNull final ViewHolder holder, @NonNull final NewsCommentBean.DataBean.CommentBean item) { final Context context = holder.itemView.getContext(); try {
String iv_avatar = item.getUser_profile_image_url();
String tv_username = item.getUser_name();
String tv_text = item.getText();
int tv_likes = item.getDigg_count(); ImageLoader.loadCenterCrop(context, iv_avatar, holder.iv_avatar, R.color.viewBackground);
holder.tv_username.setText(tv_username);
holder.tv_text.setText(tv_text);
holder.tv_likes.setText(tv_likes + "赞");
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final String content = item.getText();
final BottomSheetDialogFixed dialog = new BottomSheetDialogFixed(context);
dialog.setOwnerActivity((BaseActivity) context);
View view = ((BaseActivity) context).getLayoutInflater().inflate(R.layout.item_comment_action_sheet, null);
view.findViewById(R.id.layout_copy_text).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ClipboardManager copy = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clipData = ClipData.newPlainText("text", content);
copy.setPrimaryClip(clipData);
Snackbar.make(holder.itemView, R.string.copied_to_clipboard, Snackbar.LENGTH_SHORT).show();
dialog.dismiss();
}
});
view.findViewById(R.id.layout_share_text).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
IntentAction.send(context, content);
dialog.dismiss();
}
});
dialog.setContentView(view);
dialog.show();
}
});
} catch (Exception e) {
ErrorAction.print(e);
}
} public class ViewHolder extends RecyclerView.ViewHolder { private ImageView iv_avatar;
private TextView tv_username;
private TextView tv_text;
private TextView tv_likes; public ViewHolder(View itemView) {
super(itemView);
this.iv_avatar = itemView.findViewById(R.id.iv_avatar);
this.tv_username = itemView.findViewById(R.id.tv_username);
this.tv_text = itemView.findViewById(R.id.tv_text);
this.tv_likes = itemView.findViewById(R.id.tv_likes);
}
}
}
5.4.需要一个新闻评论每一个item的布局==>item_news_comment.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/viewBackground"> <LinearLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:foreground="?attr/selectableItemBackground"
android:orientation="vertical"
android:paddingBottom="8dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="8dp"> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"> <com.meiji.toutiao.widget.CircleImageView
android:id="@+id/iv_avatar"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_gravity="center"/> <TextView
android:id="@+id/tv_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:ellipsize="end"
android:maxLines="1"
tools:text="小恢恢的帽子"/> </LinearLayout> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:orientation="vertical"> <TextView
android:id="@+id/tv_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="光看个开头就笑的不行了,咱们中国有个传统,就是家里来客人了,要到门口迎一下,如果手里还带着礼物,那要先接过来,因为人家大老远一路带过来的,已经很累了,更何况老美不远万里带过来的呢,如果不接过来那也太不像话了,会让国际笑话中国,也有失大国风范!这也是一种礼貌,更是中华民族的传统美德!"/> <TextView
android:id="@+id/tv_likes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="end"
android:maxLines="1"
tools:text="4832赞"/> </LinearLayout>
</LinearLayout> <View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_below="@+id/content"
android:background="@color/line_divider"/> </RelativeLayout>
预览页面:
6.API请求
6.1.在IMobieNewsApi中写这个函数
/**
* 获取新闻评论
* 按热度排序
* http://is.snssdk.com/article/v53/tab_comments/?group_id=6314103921648926977&offset=0&tab_index=0
* 按时间排序
* http://is.snssdk.com/article/v53/tab_comments/?group_id=6314103921648926977&offset=0&tab_index=1
*
* @param groupId 新闻ID
* @param offset 偏移量
*/
@GET("http://is.snssdk.com/article/v53/tab_comments/")
Observable<NewsCommentBean> getNewsComment(
@Query("group_id") String groupId,
@Query("offset") int offset);
传递进来两个参数,一个是新闻Id,一个是偏移量(就是获取那些评论)。
传出去Observable<NewsCommentBean>
6.2.调用方式==>在处理器的加载数据中执行
RetrofitFactory.getRetrofit().create(IMobileNewsApi.class)
.getNewsComment(groupId, offset)
.subscribeOn(Schedulers.io())
.map(new Function<NewsCommentBean, List<NewsCommentBean.DataBean.CommentBean>>() {
@Override
public List<NewsCommentBean.DataBean.CommentBean> apply(@NonNull NewsCommentBean newsCommentBean) throws Exception {
List<NewsCommentBean.DataBean.CommentBean> data = new ArrayList<>();
for (NewsCommentBean.DataBean bean : newsCommentBean.getData()) {
data.add(bean.getComment());
}
return data;
}
})
.compose(view.<List<NewsCommentBean.DataBean.CommentBean>>bindToLife())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<NewsCommentBean.DataBean.CommentBean>>() {
@Override
public void accept(@NonNull List<NewsCommentBean.DataBean.CommentBean> list) throws Exception {
if (null != list && list.size() > 0) {
doSetAdapter(list);
} else {
doShowNoMore();
}
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
doShowNetError();
ErrorAction.print(throwable);
}
});
}
TouTiao开源项目 分析笔记16 新闻评论的更多相关文章
- TouTiao开源项目 分析笔记15 新闻详情之两种类型的实现
1.预览效果 1.1.首先看一下需要实现的效果. 第一种,文字类型新闻. 第二种,图片类型新闻. 1.2.在NewsArticleTextViewBinder中设置了点击事件 RxView.click ...
- TouTiao开源项目 分析笔记17 新闻媒体专栏
1.效果预览 1.1.要实现的效果 1.2.如何调转到新闻媒体专栏 点击右上角的用户图标. 在新闻详情页面的Fragment的菜单点击事件中触发. case R.id.action_open_medi ...
- TouTiao开源项目 分析笔记14 段子评论
1.段子页面详情 1.1.先看看预览界面吧 左边的页面已经实现了,现在的目的就是要实现点击左侧的每一个item 然后跳转到右边相应的段子详情页面. 1.2.首先肯定有右侧这个活动==>JokeC ...
- TouTiao开源项目 分析笔记2
1.Constant常量定义类 1.1.源代码 public class Constant { public static final String USER_AGENT_MOBILE = " ...
- TouTiao开源项目 分析笔记12 从总体到局部 构建视频主页面
1.构建视频主列表的整体碎片VideoTabLayout 1.1.首先创建一个VideoTabLayout package com.jasonjan.headnews.module.video; im ...
- TouTiao开源项目 分析笔记18 视频详情页面
1.效果预览 1.1.需要做到的真实效果 1.2.触发的点击事件 在MediaArticleVideoViewBinder的每一个item点击事件中: VideoContentActivity.lau ...
- TouTiao开源项目 分析笔记10 实现通用普通文章片段页面
1.RxJava的Observable数据操作符总结 1.1.Map操作符 Map操作符对原始Observable发射的没一项数据应用一个你选择的函数, 然后返回一个发射这些结果的Observable ...
- TouTiao开源项目 分析笔记20 问答详情
1.效果预览 1.1.效果预览,从问答列表开始 前面实现了从列表到内容. 这里主要讲解从内容到详情. 点击每一个回答内容,进入回答详情页面. 1.2.触发的点击事件 在WendaContentView ...
- TouTiao开源项目 分析笔记6
1.NewsChannelBean简单类笔记 1.1.Comparable接口的实现和使用 参考文章:Comparable接口的实现和使用. 因为NewsChannelBean实现了Comparabl ...
随机推荐
- HTML5 笔记之 HTML5 的常见用法介绍
阅读目录 介绍 网页标题.文章标题.文章段落 介绍 字体大小.字体颜色.字体类型.字体位置.背景颜色 介绍 插入图片 介绍 网页内的超链接.网页间的超链接 介绍 有序列表.无序列表 介绍 表格制作 介 ...
- javascript代码工具库
1. 垃圾收集 另一个块作用域非常有用的原因和闭包及回收内存垃圾的回收机制相关.这里简要说明一 下,而内部的实现原理,也就是闭包的机制会在第 5 章详细解释. 考虑以下代码: function pro ...
- vscode:快速生成html的方法
第一步:在空文档中输入! 第二步:按下tab键. 以上
- MySQL入门很简单: 2 MySQL数据类型
2. MySQL数据类型 2.1 整数类型 后面的是默认显示宽度: tinyint(4) smallint(6) mediumint(9) int(11) bigint(20) 2.2 浮点型和定点数 ...
- 设定网页最小最大宽度和高度(兼容IE6)
http://www.cnblogs.com/double-bin/archive/2011/12/19/2293093.html /* 最小寬度 */ .min_width{min-width:30 ...
- QT学习之QScript
QT中有解析Json的一个类叫QScript.貌似还有一个QJson,但听说解析的方便性不如QScript,具体没有深入探究,这里仅简单记录一下QScript的使用. 首先,主要使用到的类有QScri ...
- 【转】Xcode真机调试初体验
1. 开发者证书(Certificates) 分为开发(iOS Development)和发布(iOS Distribution)两种,无论是真机调试,还是上传到App Store都需要该证书,是一个 ...
- Unable to launch the Java Virtual Machine
看看国内的回答,http://zhidao.baidu.com/question/119993351.html 再看看国外的,http://www.mkyong.com/oracle/oracle-s ...
- CUDA线性内存分配
原文链接 概述:线性存储器可以通过cudaMalloc().cudaMallocPitch()和cudaMalloc3D()分配 1.1D线性内存分配 1 cudaMalloc(void**,int) ...
- vim常用操作整理
一.删除操作 :%s/r//g 删除DOS方式的回车^M :%s= *$== 删除行尾空白 :%s/^(.*)n1/1$/ 删除重复行 :%s/^.pdf/new.pdf/ 只是删除第一个pdf :% ...