1.构建图片主列表的整体片段PhotoTabLayout

1.1.首先创建一个PhotoTabLayout片段

public class PhotoTabLayout extends Fragment {

    private static final String TAG = "PhotoTabLayout";
private static PhotoTabLayout instance = null;
private static int pageSize = InitApp.AppContext.getResources().getStringArray(R.array.photo_id).length;
private String categoryId[] = InitApp.AppContext.getResources().getStringArray(R.array.photo_id);
private String categoryName[] = InitApp.AppContext.getResources().getStringArray(R.array.photo_name);
private TabLayout tabLayout;
private ViewPager viewPager;
private List<Fragment> fragmentList = new ArrayList<>();
private BasePagerAdapter adapter; public static PhotoTabLayout getInstance() {
if (instance == null) {
instance = new PhotoTabLayout();
}
return instance;
} @Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_photo_tab, container, false);
initView(view);
initData();
return view;
} @Override
public void onResume() {
super.onResume();
tabLayout.setBackgroundColor(SettingUtil.getInstance().getColor());
} private void initView(View view) {
tabLayout = view.findViewById(R.id.tab_layout_photo);
viewPager = view.findViewById(R.id.view_pager_photo); tabLayout.setupWithViewPager(viewPager);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
tabLayout.setBackgroundColor(SettingUtil.getInstance().getColor());
viewPager.setOffscreenPageLimit(pageSize);
} private void initData() {
for (int i = 0; i < categoryId.length; i++) {
Fragment fragment = PhotoArticleView.newInstance(categoryId[i]);
fragmentList.add(fragment);
}
adapter = new BasePagerAdapter(getChildFragmentManager(), fragmentList, categoryName);
viewPager.setAdapter(adapter);
} public void onDoubleClick() {
if (fragmentList != null && fragmentList.size() > 0) {
int item = viewPager.getCurrentItem();
((BaseListFragment) fragmentList.get(item)).onRefresh();
}
} @Override
public void onDestroy() {
if (instance != null) {
instance = null;
}
super.onDestroy();
}
}

1.2.这个片段需要一个布局fragment_photo_tab.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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <android.support.design.widget.TabLayout
android:id="@+id/tab_layout_photo"
style="@style/TabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="@style/AppTheme.AppBarOverlay"
app:tabTextColor="@color/gray">
</android.support.design.widget.TabLayout> <android.support.v4.view.ViewPager
android:id="@+id/view_pager_photo"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:layout="@layout/fragment_list">
</android.support.v4.view.ViewPager> </LinearLayout>

1.3.布局真实效果预览

  

1.4.然后就是tabLayout的静态文字

  在资源文件中values中的photo_category.xml

<?xml version="1.0" encoding="utf-8"?>
<resources> <string-array name="photo_name">
<item>全部</item>
<item>老照片</item>
<item>故事照片</item>
<item>摄影集</item>
</string-array> <string-array name="photo_id">
<item>组图</item>
<item>gallery_old_picture</item>
<item>gallery_story</item>
<item>gallery_photograthy</item>
</string-array>
</resources>

1.5.然后就是将图片主列表的4个小type用一个BasePagerAdapter联系起来

  下面的代码在上方的PhotoTabLayout.java中的一个函数中,这里再拿出来讲一下。

private void initData() {
for (int i = 0; i < categoryId.length; i++) {
//这里用了PhotoArticleView,图片中所有fragment都是用这个类,所以要新建这个类了,下面再详细讲解这个类的构造过程
Fragment fragment = PhotoArticleView.newInstance(categoryId[i]);
fragmentList.add(fragment);
}
//这里就是将文字和片段统一的过程了,最重要的就是这个BasePagerAdapter将所有片段集合,设置到viewPager的适配器中
adapter = new BasePagerAdapter(getChildFragmentManager(), fragmentList, categoryName);
viewPager.setAdapter(adapter);
}

1.6.看一下这个片段的适配器吧

  名字叫做BasePagerAdapter

public class BasePagerAdapter extends FragmentStatePagerAdapter {

    private List<Fragment> fragmentList;
private List<String> titleList; public BasePagerAdapter(FragmentManager fm, List<Fragment> fragmentList, String[] titles) {
super(fm);
this.fragmentList = fragmentList;
this.titleList = new ArrayList<>(Arrays.asList(titles));
} public BasePagerAdapter(FragmentManager fm, List<Fragment> fragmentList, List<String> titleList) {
super(fm);
this.fragmentList = fragmentList;
this.titleList = titleList;
} @Override
public Fragment getItem(int position) {
return fragmentList.get(position);
} @Override
public int getCount() {
return titleList.size();
} @Override
public CharSequence getPageTitle(int position) {
return titleList.get(position);
} @Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
} public void recreateItems(List<Fragment> fragmentList, List<String> titleList) {
this.fragmentList = fragmentList;
this.titleList = titleList;
notifyDataSetChanged();
}
}

1.7.第一阶段结束,主要完成了PhotoTabLayout这个图片主页面的布局和相应的逻辑。

  第二阶段主要处理4个分片段的布局和逻辑了。

2.图片系列的文章的基础Bean类

2.1.第一集团数据返回==>调用API返回的数据

 /**
* has_more : true
* message : success
* next : {"max_behot_time":1494154227}
* data:[[.....]]
*/

2.2.第二集团数据返回==>上面的data返回的数据

//data返回的数据 

/**
* image_url : http://p9.pstatp.com/list/640x360/1b820001767b34813c82
* media_avatar_url : http://p1.pstatp.com/large/d2a0011291a5cfef5c3
* article_genre : gallery
* is_diversion_page : false
* title : 我拍少女签约模特王纯粹少女视觉
* middle_mode : false
* gallary_image_count : 41
* image_list : [{"url":"http://p3.pstatp.com/list/640x360/1b820001767b34813c82","width":620,"url_list":[{"url":"http://p9.pstatp.com/list/640x360/1b820001767b34813c82"},{"url":"http://pb1.pstatp.com/list/640x360/1b820001767b34813c82"},{"url":"http://pb3.pstatp.com/list/640x360/1b820001767b34813c82"}],"uri":"list/640x360/1b820001767b34813c82","height":855},{"url":"http://p3.pstatp.com/list/640x360/1b8700015c172e7de742","width":1280,"url_list":[{"url":"http://p3.pstatp.com/list/1b8700015c172e7de742"},{"url":"http://pb9.pstatp.com/list/1b8700015c172e7de742"},{"url":"http://pb1.pstatp.com/list/1b8700015c172e7de742"}],"uri":"list/1b8700015c172e7de742","height":720},{"url":"http://p9.pstatp.com/list/640x360/1b8500015b6a1c897705","width":1656,"url_list":[{"url":"http://p9.pstatp.com/list/1b8500015b6a1c897705"},{"url":"http://pb1.pstatp.com/list/1b8500015b6a1c897705"},{"url":"http://pb3.pstatp.com/list/1b8500015b6a1c897705"}],"uri":"list/1b8500015b6a1c897705","height":2415}]
* more_mode : true
* behot_time : 1494158550
* source_url : /group/6408674663173767426/
* source : 我拍少女
* hot : 1
* is_feed_ad : false
* has_gallery : true
* single_mode : false
* comments_count : 1
* group_id : 6408674663173767426
* media_url : http://toutiao.com/m4439122761/
* honey : true
*/

2.3.整个PhotoArticleBean类

public class PhotoArticleBean {

    /**
* has_more : true
* message : success
* next : {"max_behot_time":1494154227}
*/ private boolean has_more;
private String message;
private NextBean next;
private List<DataBean> data; public boolean isHas_more() {
return has_more;
} public void setHas_more(boolean has_more) {
this.has_more = has_more;
} public String getMessage() {
return message;
} public void setMessage(String message) {
this.message = message;
} public NextBean getNext() {
return next;
} public void setNext(NextBean next) {
this.next = next;
} public List<DataBean> getData() {
return data;
} public void setData(List<DataBean> data) {
this.data = data;
} public static class NextBean{
private int max_behot_time;
public int getMax_behot_time(){
return max_behot_time;
}
public void setMax_behot_time(int max_behot_tim){
this.max_behot_time=max_behot_time;
}
} public static class DataBean implements Parcelable {
public static final Creator<DataBean> CREATOR = new Creator<DataBean>() {
@Override
public DataBean createFromParcel(Parcel in) {
return new DataBean(in);
} @Override
public DataBean[] newArray(int size) {
return new DataBean[size];
}
};
/**
* image_url : http://p9.pstatp.com/list/640x360/1b820001767b34813c82
* media_avatar_url : http://p1.pstatp.com/large/d2a0011291a5cfef5c3
* article_genre : gallery
* is_diversion_page : false
* title : 我拍少女签约模特王纯粹少女视觉
* middle_mode : false
* gallary_image_count : 41
* image_list : [{"url":"http://p3.pstatp.com/list/640x360/1b820001767b34813c82","width":620,"url_list":[{"url":"http://p9.pstatp.com/list/640x360/1b820001767b34813c82"},{"url":"http://pb1.pstatp.com/list/640x360/1b820001767b34813c82"},{"url":"http://pb3.pstatp.com/list/640x360/1b820001767b34813c82"}],"uri":"list/640x360/1b820001767b34813c82","height":855},{"url":"http://p3.pstatp.com/list/640x360/1b8700015c172e7de742","width":1280,"url_list":[{"url":"http://p3.pstatp.com/list/1b8700015c172e7de742"},{"url":"http://pb9.pstatp.com/list/1b8700015c172e7de742"},{"url":"http://pb1.pstatp.com/list/1b8700015c172e7de742"}],"uri":"list/1b8700015c172e7de742","height":720},{"url":"http://p9.pstatp.com/list/640x360/1b8500015b6a1c897705","width":1656,"url_list":[{"url":"http://p9.pstatp.com/list/1b8500015b6a1c897705"},{"url":"http://pb1.pstatp.com/list/1b8500015b6a1c897705"},{"url":"http://pb3.pstatp.com/list/1b8500015b6a1c897705"}],"uri":"list/1b8500015b6a1c897705","height":2415}]
* more_mode : true
* behot_time : 1494158550
* source_url : /group/6408674663173767426/
* source : 我拍少女
* hot : 1
* is_feed_ad : false
* has_gallery : true
* single_mode : false
* comments_count : 1
* group_id : 6408674663173767426
* media_url : http://toutiao.com/m4439122761/
* honey : true
*/ private String image_url;
private String media_avatar_url;
private String article_genre;
private boolean is_diversion_page;
private String title;
private boolean middle_mode;
private int gallary_image_count;
private boolean more_mode;
private int behot_time;
private String source_url;
private String source;
private int hot;
private boolean is_feed_ad;
private boolean has_gallery;
private boolean single_mode;
private int comments_count;
private String group_id;
private String media_url;
private boolean honey;
private List<ImageListBean> image_list; protected DataBean(Parcel in) {
image_url = in.readString();
media_avatar_url = in.readString();
article_genre = in.readString();
is_diversion_page = in.readByte() != 0;
title = in.readString();
middle_mode = in.readByte() != 0;
gallary_image_count = in.readInt();
more_mode = in.readByte() != 0;
behot_time = in.readInt();
source_url = in.readString();
source = in.readString();
hot = in.readInt();
is_feed_ad = in.readByte() != 0;
has_gallery = in.readByte() != 0;
single_mode = in.readByte() != 0;
comments_count = in.readInt();
group_id = in.readString();
media_url = in.readString();
honey = in.readByte() != 0;
} @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(image_url);
dest.writeString(media_avatar_url);
dest.writeString(article_genre);
dest.writeByte((byte) (is_diversion_page ? 1 : 0));
dest.writeString(title);
dest.writeByte((byte) (middle_mode ? 1 : 0));
dest.writeInt(gallary_image_count);
dest.writeByte((byte) (more_mode ? 1 : 0));
dest.writeInt(behot_time);
dest.writeString(source_url);
dest.writeString(source);
dest.writeInt(hot);
dest.writeByte((byte) (is_feed_ad ? 1 : 0));
dest.writeByte((byte) (has_gallery ? 1 : 0));
dest.writeByte((byte) (single_mode ? 1 : 0));
dest.writeInt(comments_count);
dest.writeString(group_id);
dest.writeString(media_url);
dest.writeByte((byte) (honey ? 1 : 0));
} @Override
public int describeContents() {
return 0;
} public String getImage_url() {
return image_url;
} public void setImage_url(String image_url) {
this.image_url = image_url;
} public String getMedia_avatar_url() {
return media_avatar_url;
} public void setMedia_avatar_url(String media_avatar_url) {
this.media_avatar_url = media_avatar_url;
} public String getArticle_genre() {
return article_genre;
} public void setArticle_genre(String article_genre) {
this.article_genre = article_genre;
} public boolean isIs_diversion_page() {
return is_diversion_page;
} public void setIs_diversion_page(boolean is_diversion_page) {
this.is_diversion_page = is_diversion_page;
} public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public boolean isMiddle_mode() {
return middle_mode;
} public void setMiddle_mode(boolean middle_mode) {
this.middle_mode = middle_mode;
} public int getGallary_image_count() {
return gallary_image_count;
} public void setGallary_image_count(int gallary_image_count) {
this.gallary_image_count = gallary_image_count;
} public boolean isMore_mode() {
return more_mode;
} public void setMore_mode(boolean more_mode) {
this.more_mode = more_mode;
} public int getBehot_time() {
return behot_time;
} public void setBehot_time(int behot_time) {
this.behot_time = behot_time;
} public String getSource_url() {
return source_url;
} public void setSource_url(String source_url) {
this.source_url = source_url;
} public String getSource() {
return source;
} public void setSource(String source) {
this.source = source;
} public int getHot() {
return hot;
} public void setHot(int hot) {
this.hot = hot;
} public boolean isIs_feed_ad() {
return is_feed_ad;
} public void setIs_feed_ad(boolean is_feed_ad) {
this.is_feed_ad = is_feed_ad;
} public boolean isHas_gallery() {
return has_gallery;
} public void setHas_gallery(boolean has_gallery) {
this.has_gallery = has_gallery;
} public boolean isSingle_mode() {
return single_mode;
} public void setSingle_mode(boolean single_mode) {
this.single_mode = single_mode;
} public int getComments_count() {
return comments_count;
} public void setComments_count(int comments_count) {
this.comments_count = comments_count;
} public String getGroup_id() {
return group_id;
} public void setGroup_id(String group_id) {
this.group_id = group_id;
} public String getMedia_url() {
return media_url;
} public void setMedia_url(String media_url) {
this.media_url = media_url;
} public boolean isHoney() {
return honey;
} public void setHoney(boolean honey) {
this.honey = honey;
} public List<ImageListBean> getImage_list() {
return image_list;
} public void setImage_list(List<ImageListBean> image_list) {
this.image_list = image_list;
} public static class ImageListBean {
/**
* url : http://p3.pstatp.com/list/640x360/1b820001767b34813c82
* width : 620
* url_list : [{"url":"http://p9.pstatp.com/list/640x360/1b820001767b34813c82"},{"url":"http://pb1.pstatp.com/list/640x360/1b820001767b34813c82"},{"url":"http://pb3.pstatp.com/list/640x360/1b820001767b34813c82"}]
* uri : list/640x360/1b820001767b34813c82
* height : 855
*/ private String url;
private int width;
private String uri;
private int height;
private List<UrlListBean> url_list; public String getUrl() {
return url;
} public void setUrl(String url) {
this.url = url;
} public int getWidth() {
return width;
} public void setWidth(int width) {
this.width = width;
} public String getUri() {
return uri;
} public void setUri(String uri) {
this.uri = uri;
} public int getHeight() {
return height;
} public void setHeight(int height) {
this.height = height;
} public List<UrlListBean> getUrl_list() {
return url_list;
} public void setUrl_list(List<UrlListBean> url_list) {
this.url_list = url_list;
} public static class UrlListBean {
/**
* url : http://p9.pstatp.com/list/640x360/1b820001767b34813c82
*/ private String url; public String getUrl() {
return url;
} public void setUrl(String url) {
this.url = url;
}
}
}
}
}

3.图片系列的视图以及处理器控制

3.1.最底层视图以及处理器接口 

interface IPhotoArticle {

    interface View extends IBaseListView<Presenter> {

        /**
* 请求数据
*/
void onLoadData();
} interface Presenter extends IBasePresenter { /**
* 请求数据
*/
void doLoadData(String... category); /**
* 再起请求数据
*/
void doLoadMoreData(); /**
* 设置适配器
*/
void doSetAdapter(List<PhotoArticleBean.DataBean> dataBeen); void doShowNoMore();
}
}

3.2.图片系列的视图

package com.jasonjan.headnews.module.photo;

import android.os.Bundle;
import android.view.View; import com.jasonjan.headnews.adapter.DiffCallback;
import com.jasonjan.headnews.bean.common.LoadingBean;
import com.jasonjan.headnews.main.Register;
import com.jasonjan.headnews.module.base.BaseListFragment;
import com.jasonjan.headnews.util.OnLoadMoreListener; import java.util.List; import me.drakeet.multitype.Items;
import me.drakeet.multitype.MultiTypeAdapter; /**
* Created by JasonJan on 2017/12/13.
*/ public class PhotoArticleView extends BaseListFragment<IPhotoArticle.Presenter> implements IPhotoArticle.View {
private static final String TAG = "PhotoArticleView";
private String categoryId; public static PhotoArticleView newInstance(String categoryId){
Bundle bundle=new Bundle();
bundle.putString(TAG,categoryId);
PhotoArticleView instance=new PhotoArticleView();
instance.setArguments(bundle);
return instance;
} @Override
protected void initData(){
categoryId=getArguments().getString(TAG);
} @Override
protected void initView(View view) {
super.initView(view);
adapter = new MultiTypeAdapter(oldItems);
Register.registerPhotoArticleItem(adapter);
recyclerView.setAdapter(adapter);
recyclerView.addOnScrollListener(new OnLoadMoreListener() {
@Override
public void onLoadMore() {
if (canLoadMore) {
canLoadMore = false;
presenter.doLoadMoreData();
}
}
});
} @Override
public void onLoadData() {
onShowLoading();
presenter.doLoadData(categoryId);
} @Override
public void onSetAdapter(final List<?> list) {
Items newItems = new Items(list);
newItems.add(new LoadingBean());
DiffCallback.notifyDataSetChanged(oldItems, newItems, DiffCallback.PHOTO, adapter);
oldItems.clear();
oldItems.addAll(newItems);
canLoadMore = true;
} @Override
public void setPresenter(IPhotoArticle.Presenter presenter) {
if (null == presenter) {
this.presenter = new PhotoArticlePresenter(this);
}
} }

  然后发现处理器还没有设置呢。

  然后还有视图绑定也未实现(在自定义的Register中实现)

  然后还有处理新老数据来刷新(在自定义的Diffback中实现)

3.3.图片系列的处理器

package com.jasonjan.headnews.module.photo;

import com.jasonjan.headnews.bean.photo.PhotoArticleBean;
import com.jasonjan.headnews.main.ErrorAction;
import com.jasonjan.headnews.main.RetrofitFactory;
import com.jasonjan.headnews.util.TimeUtil; import java.util.ArrayList;
import java.util.List; import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import io.reactivex.schedulers.Schedulers; /**
* Created by JasonJan on 2017/12/13.
*/ public class PhotoArticlePresenter implements IPhotoArticle.Presenter { private static final String TAG="PhotoArticlePresenter";
private IPhotoArticle.View view;
private List<PhotoArticleBean.DataBean> dataList=new ArrayList<>();
private String category;
private String time; PhotoArticlePresenter(IPhotoArticle.View view) {
this.view = view;
this.time = TimeUtil.getCurrentTimeStamp();
} @Override
public void doLoadData(String... category){
try {
if (null == this.category) {
this.category = category[0];
}
} catch (Exception e) {
ErrorAction.print(e);
} // 释放内存
if (dataList.size() > 100) {
dataList.clear();
} RetrofitFactory.getRetrofit().create(IPhotoApi.class).getPhotoArticle(this.category, time)
.subscribeOn(Schedulers.io())
.switchMap(new Function<PhotoArticleBean, Observable<PhotoArticleBean.DataBean>>() {
@Override
public Observable<PhotoArticleBean.DataBean> apply(@NonNull PhotoArticleBean photoArticleBean) throws Exception {
List<PhotoArticleBean.DataBean> data = photoArticleBean.getData();
// 移除最后一项 数据有重复
if (data.size() > 0)
data.remove(data.size() - 1);
//time = photoArticleBean.getNext().getMax_behot_time()+"";
return Observable.fromIterable(data);
}
})
.filter(new Predicate<PhotoArticleBean.DataBean>() {
@Override
public boolean test(@NonNull PhotoArticleBean.DataBean dataBean) throws Exception {
// 去除重复新闻
for (PhotoArticleBean.DataBean bean : dataList) {
if (dataBean.getTitle().equals(bean.getTitle())) {
return false;
}
}
return true;
}
})
.toList()
.compose(view.<List<PhotoArticleBean.DataBean>>bindToLife())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<PhotoArticleBean.DataBean>>() {
@Override
public void accept(@NonNull List<PhotoArticleBean.DataBean> 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(){
doLoadData();
} @Override
public void doSetAdapter(List<PhotoArticleBean.DataBean> dataBean){
dataList.addAll(dataBean);
view.onSetAdapter(dataList);
view.onHideLoading();
} @Override
public void doRefresh() {
if (dataList.size() != 0) {
dataList.clear();
time = TimeUtil.getCurrentTimeStamp()+"";
}
view.onShowLoading();
doLoadData();
} @Override
public void doShowNetError() {
view.onHideLoading();
view.onShowNetError();
} @Override
public void doShowNoMore() {
view.onHideLoading();
view.onShowNoMore();
}
}

3.4.图片系列文章的API接口请求

public interface IPhotoApi {

    /**
* 获取图片标题等信息
* http://www.toutiao.com/api/article/feed/?category=类型&as=A115C8457F69B85&cp=585F294B8845EE1&_=时间&count=30
*/
@GET("http://www.toutiao.com/api/pc/feed/?as=A1C598BB87BE7DA&cp=58B72ED7AD3A0E1")
Observable<PhotoArticleBean> getPhotoArticle(
@Query("category") String category,
@Query("max_behot_time") String maxBehotTime); /**
* 获取图片内容HTML内容
* 抓取 url 较复杂
* 详情查看 {@linkplain com.meiji.toutiao.module.photo.content.PhotoContentPresenter#doLoadData(String...)}
*/
@GET()
@Headers("User-Agent:" + Constant.USER_AGENT_PC)
Call<ResponseBody> getPhotoContentHTML(@Url String url);
}

3.5.然后是Register类中声明3中Binder

public static void registerPhotoArticleItem(@NonNull MultiTypeAdapter adapter) {
adapter.register(PhotoArticleBean.DataBean.class, new PhotoArticleViewBinder());
adapter.register(LoadingBean.class, new LoadingViewBinder());
adapter.register(LoadingEndBean.class, new LoadingEndViewBinder());
}

3.6.然后在DiffCallback中加这个类型吧

  在areItemsTheSame函数中添加Photo类型。

case PHOTO:
return ((PhotoArticleBean.DataBean) oldList.get(oldItemPosition)).getTitle().equals(
((PhotoArticleBean.DataBean) newList.get(newItemPosition)).getTitle());

  在areContentsTheSame中添加Photo类型

 case PHOTO:
return ((PhotoArticleBean.DataBean) oldList.get(oldItemPosition)).getSource_url().equals(
((PhotoArticleBean.DataBean) newList.get(newItemPosition)).getSource_url());

4.视图绑定类PhotoArticleViewBinder

4.1.视图绑定类的布局定义 

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp"
android:background="@color/viewBackground"
app:cardElevation="1dp"> <RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:foreground="?attr/selectableItemBackground"
android:padding="16dp"> <LinearLayout
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"> <com.meiji.toutiao.widget.CircleImageView
android:id="@+id/iv_media"
android:layout_width="22dp"
android:layout_height="22dp"
android:scaleType="centerCrop"/> <TextView
android:id="@+id/tv_extra"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:ellipsize="end"
android:maxLength="30"
android:maxLines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Caption"
tools:text="新闻源 - 1小时前"/> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"> <ImageView
android:id="@+id/iv_dots"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:padding="4dp"
android:scaleType="center"
app:srcCompat="@drawable/ic_dots_horizontal_grey500_24dp"
tools:ignore="ContentDescription"/>
</RelativeLayout> </LinearLayout> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/header"
android:layout_marginTop="4dp"
android:orientation="vertical"> <TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:textStyle="bold"
tools:text="看完王健林的私人飞机,再看刘强东的,刚好相差1个小目标的钱"/> <LinearLayout
android:layout_width="match_parent"
android:layout_height="82dp"
android:layout_marginTop="4dp"
android:orientation="horizontal"> <ImageView
android:id="@+id/iv_0"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="4dp"
android:layout_marginRight="4dp"
android:layout_weight="1"
android:src="@color/viewBackground"
tools:ignore="ContentDescription"/> <ImageView
android:id="@+id/iv_1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="4dp"
android:layout_marginRight="4dp"
android:layout_weight="1"
android:src="@color/viewBackground"
tools:ignore="ContentDescription"/> <ImageView
android:id="@+id/iv_2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@color/viewBackground"
tools:ignore="ContentDescription"/> </LinearLayout>
</LinearLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>

4.2.视图效果

  

4.3.视图绑定类

public class PhotoArticleViewBinder extends ItemViewBinder<PhotoArticleBean.DataBean, PhotoArticleViewBinder.ViewHolder> {

    @NonNull
@Override
protected PhotoArticleViewBinder.ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
View view = inflater.inflate(R.layout.item_photo_article, parent, false);
return new ViewHolder(view);
} @Override
protected void onBindViewHolder(@NonNull final ViewHolder holder, @NonNull final PhotoArticleBean.DataBean item) { final Context context = holder.itemView.getContext(); try {
String tv_title = item.getTitle();
if (!TextUtils.isEmpty(item.getMedia_avatar_url())) {
ImageLoader.loadCenterCrop(context, item.getMedia_avatar_url().replaceFirst("//","http://").trim(), holder.iv_media, R.color.viewBackground,R.mipmap.error_image);
} if (item.getImage_list() != null) {
int size = item.getImage_list().size();
String[] ivs = new String[size];
for (int i = 0; i < item.getImage_list().size(); i++) {
ivs[i] = item.getImage_list().get(i).getUrl().replaceFirst("//","http://").trim();
}
switch (ivs.length) {
case 1:
ImageLoader.loadCenterCrop(context, ivs[0], holder.iv_0, R.color.viewBackground,R.mipmap.error_image);
break;
case 2:
ImageLoader.loadCenterCrop(context, ivs[0], holder.iv_0, R.color.viewBackground,R.mipmap.error_image);
ImageLoader.loadCenterCrop(context, ivs[1], holder.iv_1, R.color.viewBackground,R.mipmap.error_image);
break;
case 3:
ImageLoader.loadCenterCrop(context, ivs[0], holder.iv_0, R.color.viewBackground,R.mipmap.error_image);
ImageLoader.loadCenterCrop(context, ivs[1], holder.iv_1, R.color.viewBackground,R.mipmap.error_image);
ImageLoader.loadCenterCrop(context, ivs[2], holder.iv_2, R.color.viewBackground,R.mipmap.error_image);
break;
}
Log.i("图片绑定类:","\n头像地址="+item.getMedia_avatar_url().replaceFirst("//","")+"\n图片链接="+ivs[0]+"\n"+ivs[1]+"\n"+ivs[2]); } String tv_source = item.getSource();
String tv_datetime = item.getBehot_time() + "";
String comments_count = item.getComments_count() + "评论";
if (!TextUtils.isEmpty(tv_datetime)) {
tv_datetime = TimeUtil.getTimeStampAgo(tv_datetime);
}
holder.tv_title.setText(tv_title);
holder.tv_title.setTextSize(SettingUtil.getInstance().getTextSize());
holder.tv_extra.setText(tv_source + " - " + comments_count + " - " + tv_datetime);
holder.iv_dots.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
PopupMenu popupMenu = new PopupMenu(context,
holder.iv_dots, Gravity.END, 0, R.style.MyPopupMenu);
popupMenu.inflate(R.menu.menu_share);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menu) {
int itemId = menu.getItemId();
if (itemId == R.id.action_share) {
String shareUrl = item.getSource_url();
if (!shareUrl.contains("toutiao")) {
shareUrl = "http://toutiao.com" + shareUrl;
}
IntentAction.send(context, item.getTitle() + "\n" + shareUrl);
}
return false;
}
});
popupMenu.show();
}
}); RxView.clicks(holder.itemView)
.throttleFirst(1, TimeUnit.SECONDS)
.subscribe(new Consumer<Object>() {
@Override
public void accept(@io.reactivex.annotations.NonNull Object o) throws Exception {
PhotoContentActivity.launch(item);
}
});
} catch (Exception e) {
ErrorAction.print(e);
}
} public class ViewHolder extends RecyclerView.ViewHolder { private CircleImageView iv_media;
private TextView tv_extra;
private TextView tv_title;
private ImageView iv_0;
private ImageView iv_1;
private ImageView iv_2;
private ImageView iv_dots; public ViewHolder(View itemView) {
super(itemView);
this.iv_media = itemView.findViewById(R.id.iv_media);
this.tv_extra = itemView.findViewById(R.id.tv_extra);
this.tv_title = itemView.findViewById(R.id.tv_title);
this.iv_0 = itemView.findViewById(R.id.iv_0);
this.iv_1 = itemView.findViewById(R.id.iv_1);
this.iv_2 = itemView.findViewById(R.id.iv_2);
this.iv_dots = itemView.findViewById(R.id.iv_dots);
}
}
}

5.目前效果预览

5.1.目前完成的工作

  新闻的三种大类型

  图片的一种大类型,这种大类型有4个分类,为全部、老照片、故事照片和摄影集。

  但是每种类型的评论以及详细页面还未实现。

  因为图片调用今日头条的API不稳定,有时候可以获得数据,有时候无法获得。

  所以这里是无法确保每次刷新都有新的数据。

5.2.手机真实数据预览

  

TouTiao开源项目 分析笔记11 以总体到局部的思路 构建图片主列表的更多相关文章

  1. TouTiao开源项目 分析笔记12 从总体到局部 构建视频主页面

    1.构建视频主列表的整体碎片VideoTabLayout 1.1.首先创建一个VideoTabLayout package com.jasonjan.headnews.module.video; im ...

  2. TouTiao开源项目 分析笔记2

    1.Constant常量定义类 1.1.源代码 public class Constant { public static final String USER_AGENT_MOBILE = " ...

  3. TouTiao开源项目 分析笔记9 实现一个问答主页面

    1.根据API返回创建几个基础的Bean 1.1.WendaArticleDataBean类 API返回的数据如下: /** * cell_type : 36 * extra : {"wen ...

  4. TouTiao开源项目 分析笔记6

    1.NewsChannelBean简单类笔记 1.1.Comparable接口的实现和使用 参考文章:Comparable接口的实现和使用. 因为NewsChannelBean实现了Comparabl ...

  5. TouTiao开源项目 分析笔记4==>一个简单APP 整体常用框架

    1.效果预览 1.1.如下图所以,到目前为止所有的功能. 2.从InitApp开始->SplashActivity->MainActivity 2.1.InitApp源代码.这是整个项目的 ...

  6. TouTiao开源项目 分析笔记15 新闻详情之两种类型的实现

    1.预览效果 1.1.首先看一下需要实现的效果. 第一种,文字类型新闻. 第二种,图片类型新闻. 1.2.在NewsArticleTextViewBinder中设置了点击事件 RxView.click ...

  7. TouTiao开源项目 分析笔记10 实现通用普通文章片段页面

    1.RxJava的Observable数据操作符总结 1.1.Map操作符 Map操作符对原始Observable发射的没一项数据应用一个你选择的函数, 然后返回一个发射这些结果的Observable ...

  8. TouTiao开源项目 分析笔记18 视频详情页面

    1.效果预览 1.1.需要做到的真实效果 1.2.触发的点击事件 在MediaArticleVideoViewBinder的每一个item点击事件中: VideoContentActivity.lau ...

  9. TouTiao开源项目 分析笔记17 新闻媒体专栏

    1.效果预览 1.1.要实现的效果 1.2.如何调转到新闻媒体专栏 点击右上角的用户图标. 在新闻详情页面的Fragment的菜单点击事件中触发. case R.id.action_open_medi ...

随机推荐

  1. HCNA配置console线路密码aaa认证

    Please check whether system data has been changed, and save data in time Configuration console time ...

  2. COGS 146. [USACO Jan08] 贝茜的晨练计划

    ★☆   输入文件:cowrun.in   输出文件:cowrun.out   简单对比时间限制:1 s   内存限制:32 MB 奶牛们打算通过锻炼来培养自己的运动细胞,作为其中的一员,贝茜选择的运 ...

  3. Objectbox Box的getAll() 函数返回emptylist() 未判断导致崩溃

    最近使用了Objectbox作为新项目的数据库后台,Greendao开发团队新力作,但是Objectbox算是比较新的一个东西,现在资料也不多. 今天跟大家分享一个关于Box类的getAll()函数的 ...

  4. MySQL入门很简单: 3 操作数据库

    登陆:mysq -u root -p 0409 1). 创建, 删除数据库 SHOW DATABASES; 显示已经存在的数据率 CREATE DATABASES 数据库名: 创建数据库 DROP D ...

  5. 504. Inverted Index (Map Reduce) lintcode

    https://www.lintcode.com/problem/inverted-index-map-reduce/description -- decription of the map redu ...

  6. 将Apache2.4手动安装成Windows的服务

    将Apache2.4手动安装成Windows的服务 可以选择在安装Apache时自动将其安装为一个服务.如果选择"for all users",那么Apache将会被安装为服务. ...

  7. 前端高质量知识(四)-JS详细图解作用域链与闭包

    攻克闭包难题 初学JavaScript的时候,我在学习闭包上,走了很多弯路.而这次重新回过头来对基础知识进行梳理,要讲清楚闭包,也是一个非常大的挑战. 闭包有多重要?如果你是初入前端的朋友,我没有办法 ...

  8. 谷歌Web中文开发手冊:3响应式

    https://developers.google.com/web/fundamentals/getting-started/your-first-multi-screen-site/responsi ...

  9. 转:SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)

    转:https://www.cnblogs.com/zyw-205520/p/4771253.html 1.基本概念   1.1.Spring Spring是一个开源框架,Spring是于2003 年 ...

  10. maven没有servlet(创建servlet后报错)

    maven不能创建servlet 解决方案 方案一 在项目的iml进行指定根目录 <sourceRoots> <root url="file://$MODULE_DIR$/ ...