TouTiao开源项目 分析笔记12 从总体到局部 构建视频主页面
1.构建视频主列表的整体碎片VideoTabLayout
1.1.首先创建一个VideoTabLayout
package com.jasonjan.headnews.module.video; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.jasonjan.headnews.R; import com.jasonjan.headnews.global.InitApp; import com.jasonjan.headnews.adapter.BasePagerAdapter; import com.jasonjan.headnews.test.Test_Fragment; import com.jasonjan.headnews.util.SettingUtil; import java.util.ArrayList; import java.util.List; /** * Created by JasonJan on 2017/12/1. */ public class VideoTabLayout extends Fragment { private static VideoTabLayout instance = null; private static int pageSize = InitApp.AppContext.getResources().getStringArray(R.array.mobile_video_id).length; private String categoryId[] = InitApp.AppContext.getResources().getStringArray(R.array.mobile_video_id); private String categoryName[] = InitApp.AppContext.getResources().getStringArray(R.array.mobile_video_name); private TabLayout tabLayout; private ViewPager viewPager; private List<Fragment> fragmentList = new ArrayList<>(); private BasePagerAdapter adapter; public static VideoTabLayout getInstance() { if (instance == null) { instance = new VideoTabLayout(); } return instance; } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_video_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_video); viewPager = view.findViewById(R.id.view_pager_video); 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 = VideoArticleView.newInstance(categoryId[i]); fragmentList.add(fragment); } adapter = new BasePagerAdapter(getChildFragmentManager(), fragmentList, categoryName); viewPager.setAdapter(adapter); } @Override public void onDestroy() { if (instance != null) { instance = null; } super.onDestroy(); } }
这里先声明视频中的小碎片名称为:VideoArticleView。
后面详细分析这个Fragment。主要就是视频的一些小分类。用的是同一种布局方式。
1.2.这个片段需要一个布局fragment_video_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_video" 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_video" 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中的mobile_video_category.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="mobile_video_name"> <item>推荐</item> <item>音乐</item> <item>搞笑</item> <item>社会</item> <item>小品</item> <item>生活</item> <item>影视</item> <item>娱乐</item> <item>呆萌</item> <item>游戏</item> <item>原创</item> <item>开眼</item> </string-array> <string-array name="mobile_video_id"> <item>video</item> <item>subv_voice</item> <item>subv_funny</item> <item>subv_society</item> <item>subv_comedy</item> <item>subv_life</item> <item>subv_movie</item> <item>subv_entertainment</item> <item>subv_cute</item> <item>subv_game</item> <item>subv_boutique</item> <item>subv_broaden_view</item> </string-array> </resources>
1.5.然后就是将视频主列表的十二种类型用一个BasePagerAdapter联系起来
下面的代码在上方的VideoTabLayout.java中的一个函数中,这里再重复拿出来讲一下。
private void initData() { for (int i = 0; i < categoryId.length; i++) { Fragment fragment = VideoArticleView.newInstance(categoryId[i]); fragmentList.add(fragment); } 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.第一阶段结束,主要完成了VideoTabLayout这个视频主页面和相应的逻辑。
第二阶段主要处理12个分片段的布局和逻辑了。
2.视频系列的文章的基础Bean类
2.1.第一集团数据返回==>调用API后返回的数据(包括很多杂项)
/** * data : {"status":10,"user_id":"toutiao","video_id":"f2aeddda2a894e53bb3f2cf98994aadb","big_thumbs":[{"img_num":16,"img_url":"https://p1.pstatp.com/origin/19cc000499f3a6986d59","img_x_size":160,"img_y_size":90,"img_x_len":1,"img_y_len":16}],"video_duration":84.8,"video_list":{"video_1":{"backup_url_1":"aHR0cDovL3Y3LnBzdGF0cC5jb20vNWE2YzA4ZmJjZWQxZmIzY2ZhMDdkZGE3Zjg0ZTNkZDUvNThkZGJlMjAvdmlkZW8vbS8xMTQ0YzNiMDAwMDBjMWU1MWIwMWQ1ZjIyMGE0MzMyMTUyNGQwOTQ0MjU5MDI5NmU1NDI3Yjc5NGNlLw==","bitrate":369405,"definition":"360p","main_url":"aHR0cDovL3Y2LjM2NXlnLmNvbS92aWRlby9tLzExNDRjM2IwMDAwMGMxZTUxYjAxZDVmMjIwYTQzMzIxNTI0ZDA5NDQyNTkwMjk2ZTU0MjdiNzk0Y2UvP0V4cGlyZXM9MTQ5MDkzMDczNiZBV1NBY2Nlc3NLZXlJZD1xaDBoOVRkY0VNb1Myb1BqN2FLWCZTaWduYXR1cmU9WWNmakZDNnMxSHFhQ0NxeVZMd3ZkRWNlcXg0JTNE","preload_interval":25,"preload_max_step":10,"preload_min_step":5,"preload_size":327680,"size":4630326,"socket_buffer":221643000,"user_video_proxy":1,"vheight":360,"vtype":"mp4","vwidth":640},"video_2":{"backup_url_1":"aHR0cDovL3Y3LnBzdGF0cC5jb20vNTk0ZTZjNDZjMjliZDkxY2EwZWJhMTFkM2RlMGIxN2EvNThkZGJlMjAvdmlkZW8vbS8yMjBlNmU2MjY3Mjg4NDU0YzkwOTFjOGYyMTZlZThiOWEwMjExNDRiZjAwMDAwMDZmNTE3YjkxMTk1Lw==","bitrate":577524,"definition":"480p","main_url":"aHR0cDovL3Y2LjM2NXlnLmNvbS92aWRlby9tLzIyMGU2ZTYyNjcyODg0NTRjOTA5MWM4ZjIxNmVlOGI5YTAyMTE0NGJmMDAwMDAwNmY1MTdiOTExOTUvP0V4cGlyZXM9MTQ5MDkzMDczNiZBV1NBY2Nlc3NLZXlJZD1xaDBoOVRkY0VNb1Myb1BqN2FLWCZTaWduYXR1cmU9JTJGbEtPMld4QVVtcUtqUGo4TWw5cFpxaFNSeEklM0Q=","preload_interval":25,"preload_max_step":10,"preload_min_step":5,"preload_size":327680,"size":6836189,"socket_buffer":346514400,"user_video_proxy":1,"vheight":480,"vtype":"mp4","vwidth":854},"video_3":{"backup_url_1":"aHR0cDovL3Y3LnBzdGF0cC5jb20vNzM4NTJiOTYxNDgyMzc0MDY2NWIyN2VkODZhNWVhMTEvNThkZGJlMjAvdmlkZW8vbS8yMjA0NTViMDUyMjFjYTg0MDAxOWFjZjkwZDNmZGFmZTNhZDExNDQ4ZGMwMDAwMjRkOTFkNmZkNzZhLw==","bitrate":1274484,"definition":"720p","main_url":"aHR0cDovL3YzLjM2NXlnLmNvbS83Mzg1MmI5NjE0ODIzNzQwNjY1YjI3ZWQ4NmE1ZWExMS81OGRkYmUyMC92aWRlby9tLzIyMDQ1NWIwNTIyMWNhODQwMDE5YWNmOTBkM2ZkYWZlM2FkMTE0NDhkYzAwMDAyNGQ5MWQ2ZmQ3NmEv","preload_interval":25,"preload_max_step":10,"preload_min_step":5,"preload_size":327680,"size":14223659,"socket_buffer":764690400,"user_video_proxy":1,"vheight":720,"vtype":"mp4","vwidth":1280}}} * message : success * code : 0 * total : 3 */
2.2.第二集团数据返回==>处理上方的data中的数据
/** * status : 10 * user_id : toutiao * video_id : f2aeddda2a894e53bb3f2cf98994aadb * big_thumbs : [{"img_num":16,"img_url":"https://p1.pstatp.com/origin/19cc000499f3a6986d59","img_x_size":160,"img_y_size":90,"img_x_len":1,"img_y_len":16}] * video_duration : 84.8 * video_list : {"video_1":{"backup_url_1":"aHR0cDovL3Y3LnBzdGF0cC5jb20vNWE2YzA4ZmJjZWQxZmIzY2ZhMDdkZGE3Zjg0ZTNkZDUvNThkZGJlMjAvdmlkZW8vbS8xMTQ0YzNiMDAwMDBjMWU1MWIwMWQ1ZjIyMGE0MzMyMTUyNGQwOTQ0MjU5MDI5NmU1NDI3Yjc5NGNlLw==","bitrate":369405,"definition":"360p","main_url":"aHR0cDovL3Y2LjM2NXlnLmNvbS92aWRlby9tLzExNDRjM2IwMDAwMGMxZTUxYjAxZDVmMjIwYTQzMzIxNTI0ZDA5NDQyNTkwMjk2ZTU0MjdiNzk0Y2UvP0V4cGlyZXM9MTQ5MDkzMDczNiZBV1NBY2Nlc3NLZXlJZD1xaDBoOVRkY0VNb1Myb1BqN2FLWCZTaWduYXR1cmU9WWNmakZDNnMxSHFhQ0NxeVZMd3ZkRWNlcXg0JTNE","preload_interval":25,"preload_max_step":10,"preload_min_step":5,"preload_size":327680,"size":4630326,"socket_buffer":221643000,"user_video_proxy":1,"vheight":360,"vtype":"mp4","vwidth":640},"video_2":{"backup_url_1":"aHR0cDovL3Y3LnBzdGF0cC5jb20vNTk0ZTZjNDZjMjliZDkxY2EwZWJhMTFkM2RlMGIxN2EvNThkZGJlMjAvdmlkZW8vbS8yMjBlNmU2MjY3Mjg4NDU0YzkwOTFjOGYyMTZlZThiOWEwMjExNDRiZjAwMDAwMDZmNTE3YjkxMTk1Lw==","bitrate":577524,"definition":"480p","main_url":"aHR0cDovL3Y2LjM2NXlnLmNvbS92aWRlby9tLzIyMGU2ZTYyNjcyODg0NTRjOTA5MWM4ZjIxNmVlOGI5YTAyMTE0NGJmMDAwMDAwNmY1MTdiOTExOTUvP0V4cGlyZXM9MTQ5MDkzMDczNiZBV1NBY2Nlc3NLZXlJZD1xaDBoOVRkY0VNb1Myb1BqN2FLWCZTaWduYXR1cmU9JTJGbEtPMld4QVVtcUtqUGo4TWw5cFpxaFNSeEklM0Q=","preload_interval":25,"preload_max_step":10,"preload_min_step":5,"preload_size":327680,"size":6836189,"socket_buffer":346514400,"user_video_proxy":1,"vheight":480,"vtype":"mp4","vwidth":854},"video_3":{"backup_url_1":"aHR0cDovL3Y3LnBzdGF0cC5jb20vNzM4NTJiOTYxNDgyMzc0MDY2NWIyN2VkODZhNWVhMTEvNThkZGJlMjAvdmlkZW8vbS8yMjA0NTViMDUyMjFjYTg0MDAxOWFjZjkwZDNmZGFmZTNhZDExNDQ4ZGMwMDAwMjRkOTFkNmZkNzZhLw==","bitrate":1274484,"definition":"720p","main_url":"aHR0cDovL3YzLjM2NXlnLmNvbS83Mzg1MmI5NjE0ODIzNzQwNjY1YjI3ZWQ4NmE1ZWExMS81OGRkYmUyMC92aWRlby9tLzIyMDQ1NWIwNTIyMWNhODQwMDE5YWNmOTBkM2ZkYWZlM2FkMTE0NDhkYzAwMDAyNGQ5MWQ2ZmQ3NmEv","preload_interval":25,"preload_max_step":10,"preload_min_step":5,"preload_size":327680,"size":14223659,"socket_buffer":764690400,"user_video_proxy":1,"vheight":720,"vtype":"mp4","vwidth":1280}} */
2.3.整个VideoContentBean类
package com.jasonjan.headnews.bean.video; import java.util.List; /** * Created by JasonJan on 2017/12/14. */ public class VideoContentBean { /** * data : {"status":10,"user_id":"toutiao","video_id":"f2aeddda2a894e53bb3f2cf98994aadb","big_thumbs":[{"img_num":16,"img_url":"https://p1.pstatp.com/origin/19cc000499f3a6986d59","img_x_size":160,"img_y_size":90,"img_x_len":1,"img_y_len":16}],"video_duration":84.8,"video_list":{"video_1":{"backup_url_1":"aHR0cDovL3Y3LnBzdGF0cC5jb20vNWE2YzA4ZmJjZWQxZmIzY2ZhMDdkZGE3Zjg0ZTNkZDUvNThkZGJlMjAvdmlkZW8vbS8xMTQ0YzNiMDAwMDBjMWU1MWIwMWQ1ZjIyMGE0MzMyMTUyNGQwOTQ0MjU5MDI5NmU1NDI3Yjc5NGNlLw==","bitrate":369405,"definition":"360p","main_url":"aHR0cDovL3Y2LjM2NXlnLmNvbS92aWRlby9tLzExNDRjM2IwMDAwMGMxZTUxYjAxZDVmMjIwYTQzMzIxNTI0ZDA5NDQyNTkwMjk2ZTU0MjdiNzk0Y2UvP0V4cGlyZXM9MTQ5MDkzMDczNiZBV1NBY2Nlc3NLZXlJZD1xaDBoOVRkY0VNb1Myb1BqN2FLWCZTaWduYXR1cmU9WWNmakZDNnMxSHFhQ0NxeVZMd3ZkRWNlcXg0JTNE","preload_interval":25,"preload_max_step":10,"preload_min_step":5,"preload_size":327680,"size":4630326,"socket_buffer":221643000,"user_video_proxy":1,"vheight":360,"vtype":"mp4","vwidth":640},"video_2":{"backup_url_1":"aHR0cDovL3Y3LnBzdGF0cC5jb20vNTk0ZTZjNDZjMjliZDkxY2EwZWJhMTFkM2RlMGIxN2EvNThkZGJlMjAvdmlkZW8vbS8yMjBlNmU2MjY3Mjg4NDU0YzkwOTFjOGYyMTZlZThiOWEwMjExNDRiZjAwMDAwMDZmNTE3YjkxMTk1Lw==","bitrate":577524,"definition":"480p","main_url":"aHR0cDovL3Y2LjM2NXlnLmNvbS92aWRlby9tLzIyMGU2ZTYyNjcyODg0NTRjOTA5MWM4ZjIxNmVlOGI5YTAyMTE0NGJmMDAwMDAwNmY1MTdiOTExOTUvP0V4cGlyZXM9MTQ5MDkzMDczNiZBV1NBY2Nlc3NLZXlJZD1xaDBoOVRkY0VNb1Myb1BqN2FLWCZTaWduYXR1cmU9JTJGbEtPMld4QVVtcUtqUGo4TWw5cFpxaFNSeEklM0Q=","preload_interval":25,"preload_max_step":10,"preload_min_step":5,"preload_size":327680,"size":6836189,"socket_buffer":346514400,"user_video_proxy":1,"vheight":480,"vtype":"mp4","vwidth":854},"video_3":{"backup_url_1":"aHR0cDovL3Y3LnBzdGF0cC5jb20vNzM4NTJiOTYxNDgyMzc0MDY2NWIyN2VkODZhNWVhMTEvNThkZGJlMjAvdmlkZW8vbS8yMjA0NTViMDUyMjFjYTg0MDAxOWFjZjkwZDNmZGFmZTNhZDExNDQ4ZGMwMDAwMjRkOTFkNmZkNzZhLw==","bitrate":1274484,"definition":"720p","main_url":"aHR0cDovL3YzLjM2NXlnLmNvbS83Mzg1MmI5NjE0ODIzNzQwNjY1YjI3ZWQ4NmE1ZWExMS81OGRkYmUyMC92aWRlby9tLzIyMDQ1NWIwNTIyMWNhODQwMDE5YWNmOTBkM2ZkYWZlM2FkMTE0NDhkYzAwMDAyNGQ5MWQ2ZmQ3NmEv","preload_interval":25,"preload_max_step":10,"preload_min_step":5,"preload_size":327680,"size":14223659,"socket_buffer":764690400,"user_video_proxy":1,"vheight":720,"vtype":"mp4","vwidth":1280}}} * message : success * code : 0 * total : 3 */ private DataBean data; private String message; private int code; private int total; public DataBean getData() { return data; } public void setData(DataBean data) { this.data = data; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } public static class DataBean { /** * status : 10 * user_id : toutiao * video_id : f2aeddda2a894e53bb3f2cf98994aadb * big_thumbs : [{"img_num":16,"img_url":"https://p1.pstatp.com/origin/19cc000499f3a6986d59","img_x_size":160,"img_y_size":90,"img_x_len":1,"img_y_len":16}] * video_duration : 84.8 * video_list : {"video_1":{"backup_url_1":"aHR0cDovL3Y3LnBzdGF0cC5jb20vNWE2YzA4ZmJjZWQxZmIzY2ZhMDdkZGE3Zjg0ZTNkZDUvNThkZGJlMjAvdmlkZW8vbS8xMTQ0YzNiMDAwMDBjMWU1MWIwMWQ1ZjIyMGE0MzMyMTUyNGQwOTQ0MjU5MDI5NmU1NDI3Yjc5NGNlLw==","bitrate":369405,"definition":"360p","main_url":"aHR0cDovL3Y2LjM2NXlnLmNvbS92aWRlby9tLzExNDRjM2IwMDAwMGMxZTUxYjAxZDVmMjIwYTQzMzIxNTI0ZDA5NDQyNTkwMjk2ZTU0MjdiNzk0Y2UvP0V4cGlyZXM9MTQ5MDkzMDczNiZBV1NBY2Nlc3NLZXlJZD1xaDBoOVRkY0VNb1Myb1BqN2FLWCZTaWduYXR1cmU9WWNmakZDNnMxSHFhQ0NxeVZMd3ZkRWNlcXg0JTNE","preload_interval":25,"preload_max_step":10,"preload_min_step":5,"preload_size":327680,"size":4630326,"socket_buffer":221643000,"user_video_proxy":1,"vheight":360,"vtype":"mp4","vwidth":640},"video_2":{"backup_url_1":"aHR0cDovL3Y3LnBzdGF0cC5jb20vNTk0ZTZjNDZjMjliZDkxY2EwZWJhMTFkM2RlMGIxN2EvNThkZGJlMjAvdmlkZW8vbS8yMjBlNmU2MjY3Mjg4NDU0YzkwOTFjOGYyMTZlZThiOWEwMjExNDRiZjAwMDAwMDZmNTE3YjkxMTk1Lw==","bitrate":577524,"definition":"480p","main_url":"aHR0cDovL3Y2LjM2NXlnLmNvbS92aWRlby9tLzIyMGU2ZTYyNjcyODg0NTRjOTA5MWM4ZjIxNmVlOGI5YTAyMTE0NGJmMDAwMDAwNmY1MTdiOTExOTUvP0V4cGlyZXM9MTQ5MDkzMDczNiZBV1NBY2Nlc3NLZXlJZD1xaDBoOVRkY0VNb1Myb1BqN2FLWCZTaWduYXR1cmU9JTJGbEtPMld4QVVtcUtqUGo4TWw5cFpxaFNSeEklM0Q=","preload_interval":25,"preload_max_step":10,"preload_min_step":5,"preload_size":327680,"size":6836189,"socket_buffer":346514400,"user_video_proxy":1,"vheight":480,"vtype":"mp4","vwidth":854},"video_3":{"backup_url_1":"aHR0cDovL3Y3LnBzdGF0cC5jb20vNzM4NTJiOTYxNDgyMzc0MDY2NWIyN2VkODZhNWVhMTEvNThkZGJlMjAvdmlkZW8vbS8yMjA0NTViMDUyMjFjYTg0MDAxOWFjZjkwZDNmZGFmZTNhZDExNDQ4ZGMwMDAwMjRkOTFkNmZkNzZhLw==","bitrate":1274484,"definition":"720p","main_url":"aHR0cDovL3YzLjM2NXlnLmNvbS83Mzg1MmI5NjE0ODIzNzQwNjY1YjI3ZWQ4NmE1ZWExMS81OGRkYmUyMC92aWRlby9tLzIyMDQ1NWIwNTIyMWNhODQwMDE5YWNmOTBkM2ZkYWZlM2FkMTE0NDhkYzAwMDAyNGQ5MWQ2ZmQ3NmEv","preload_interval":25,"preload_max_step":10,"preload_min_step":5,"preload_size":327680,"size":14223659,"socket_buffer":764690400,"user_video_proxy":1,"vheight":720,"vtype":"mp4","vwidth":1280}} */ private int status; private String user_id; private String video_id; private double video_duration; private VideoListBean video_list; private List<BigThumbsBean> big_thumbs; public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public String getUser_id() { return user_id; } public void setUser_id(String user_id) { this.user_id = user_id; } public String getVideo_id() { return video_id; } public void setVideo_id(String video_id) { this.video_id = video_id; } public double getVideo_duration() { return video_duration; } public void setVideo_duration(double video_duration) { this.video_duration = video_duration; } public VideoListBean getVideo_list() { return video_list; } public void setVideo_list(VideoListBean video_list) { this.video_list = video_list; } public List<BigThumbsBean> getBig_thumbs() { return big_thumbs; } public void setBig_thumbs(List<BigThumbsBean> big_thumbs) { this.big_thumbs = big_thumbs; } public static class VideoListBean { /** * video_1 : {"backup_url_1":"aHR0cDovL3Y3LnBzdGF0cC5jb20vNWE2YzA4ZmJjZWQxZmIzY2ZhMDdkZGE3Zjg0ZTNkZDUvNThkZGJlMjAvdmlkZW8vbS8xMTQ0YzNiMDAwMDBjMWU1MWIwMWQ1ZjIyMGE0MzMyMTUyNGQwOTQ0MjU5MDI5NmU1NDI3Yjc5NGNlLw==","bitrate":369405,"definition":"360p","main_url":"aHR0cDovL3Y2LjM2NXlnLmNvbS92aWRlby9tLzExNDRjM2IwMDAwMGMxZTUxYjAxZDVmMjIwYTQzMzIxNTI0ZDA5NDQyNTkwMjk2ZTU0MjdiNzk0Y2UvP0V4cGlyZXM9MTQ5MDkzMDczNiZBV1NBY2Nlc3NLZXlJZD1xaDBoOVRkY0VNb1Myb1BqN2FLWCZTaWduYXR1cmU9WWNmakZDNnMxSHFhQ0NxeVZMd3ZkRWNlcXg0JTNE","preload_interval":25,"preload_max_step":10,"preload_min_step":5,"preload_size":327680,"size":4630326,"socket_buffer":221643000,"user_video_proxy":1,"vheight":360,"vtype":"mp4","vwidth":640} * video_2 : {"backup_url_1":"aHR0cDovL3Y3LnBzdGF0cC5jb20vNTk0ZTZjNDZjMjliZDkxY2EwZWJhMTFkM2RlMGIxN2EvNThkZGJlMjAvdmlkZW8vbS8yMjBlNmU2MjY3Mjg4NDU0YzkwOTFjOGYyMTZlZThiOWEwMjExNDRiZjAwMDAwMDZmNTE3YjkxMTk1Lw==","bitrate":577524,"definition":"480p","main_url":"aHR0cDovL3Y2LjM2NXlnLmNvbS92aWRlby9tLzIyMGU2ZTYyNjcyODg0NTRjOTA5MWM4ZjIxNmVlOGI5YTAyMTE0NGJmMDAwMDAwNmY1MTdiOTExOTUvP0V4cGlyZXM9MTQ5MDkzMDczNiZBV1NBY2Nlc3NLZXlJZD1xaDBoOVRkY0VNb1Myb1BqN2FLWCZTaWduYXR1cmU9JTJGbEtPMld4QVVtcUtqUGo4TWw5cFpxaFNSeEklM0Q=","preload_interval":25,"preload_max_step":10,"preload_min_step":5,"preload_size":327680,"size":6836189,"socket_buffer":346514400,"user_video_proxy":1,"vheight":480,"vtype":"mp4","vwidth":854} * video_3 : {"backup_url_1":"aHR0cDovL3Y3LnBzdGF0cC5jb20vNzM4NTJiOTYxNDgyMzc0MDY2NWIyN2VkODZhNWVhMTEvNThkZGJlMjAvdmlkZW8vbS8yMjA0NTViMDUyMjFjYTg0MDAxOWFjZjkwZDNmZGFmZTNhZDExNDQ4ZGMwMDAwMjRkOTFkNmZkNzZhLw==","bitrate":1274484,"definition":"720p","main_url":"aHR0cDovL3YzLjM2NXlnLmNvbS83Mzg1MmI5NjE0ODIzNzQwNjY1YjI3ZWQ4NmE1ZWExMS81OGRkYmUyMC92aWRlby9tLzIyMDQ1NWIwNTIyMWNhODQwMDE5YWNmOTBkM2ZkYWZlM2FkMTE0NDhkYzAwMDAyNGQ5MWQ2ZmQ3NmEv","preload_interval":25,"preload_max_step":10,"preload_min_step":5,"preload_size":327680,"size":14223659,"socket_buffer":764690400,"user_video_proxy":1,"vheight":720,"vtype":"mp4","vwidth":1280} */ private Video1Bean video_1; private Video2Bean video_2; private Video3Bean video_3; public Video1Bean getVideo_1() { return video_1; } public void setVideo_1(Video1Bean video_1) { this.video_1 = video_1; } public Video2Bean getVideo_2() { return video_2; } public void setVideo_2(Video2Bean video_2) { this.video_2 = video_2; } public Video3Bean getVideo_3() { return video_3; } public void setVideo_3(Video3Bean video_3) { this.video_3 = video_3; } public static class Video1Bean { /** * backup_url_1 : aHR0cDovL3Y3LnBzdGF0cC5jb20vNWE2YzA4ZmJjZWQxZmIzY2ZhMDdkZGE3Zjg0ZTNkZDUvNThkZGJlMjAvdmlkZW8vbS8xMTQ0YzNiMDAwMDBjMWU1MWIwMWQ1ZjIyMGE0MzMyMTUyNGQwOTQ0MjU5MDI5NmU1NDI3Yjc5NGNlLw== * bitrate : 369405 * definition : 360p * main_url : aHR0cDovL3Y2LjM2NXlnLmNvbS92aWRlby9tLzExNDRjM2IwMDAwMGMxZTUxYjAxZDVmMjIwYTQzMzIxNTI0ZDA5NDQyNTkwMjk2ZTU0MjdiNzk0Y2UvP0V4cGlyZXM9MTQ5MDkzMDczNiZBV1NBY2Nlc3NLZXlJZD1xaDBoOVRkY0VNb1Myb1BqN2FLWCZTaWduYXR1cmU9WWNmakZDNnMxSHFhQ0NxeVZMd3ZkRWNlcXg0JTNE * preload_interval : 25 * preload_max_step : 10 * preload_min_step : 5 * preload_size : 327680 * size : 4630326 * socket_buffer : 221643000 * user_video_proxy : 1 * vheight : 360 * vtype : mp4 * vwidth : 640 */ private String backup_url_1; private int bitrate; private String definition; private String main_url; private int preload_interval; private int preload_max_step; private int preload_min_step; private int preload_size; private int size; private int socket_buffer; private int user_video_proxy; private int vheight; private String vtype; private int vwidth; public String getBackup_url_1() { return backup_url_1; } public void setBackup_url_1(String backup_url_1) { this.backup_url_1 = backup_url_1; } public int getBitrate() { return bitrate; } public void setBitrate(int bitrate) { this.bitrate = bitrate; } public String getDefinition() { return definition; } public void setDefinition(String definition) { this.definition = definition; } public String getMain_url() { return main_url; } public void setMain_url(String main_url) { this.main_url = main_url; } public int getPreload_interval() { return preload_interval; } public void setPreload_interval(int preload_interval) { this.preload_interval = preload_interval; } public int getPreload_max_step() { return preload_max_step; } public void setPreload_max_step(int preload_max_step) { this.preload_max_step = preload_max_step; } public int getPreload_min_step() { return preload_min_step; } public void setPreload_min_step(int preload_min_step) { this.preload_min_step = preload_min_step; } public int getPreload_size() { return preload_size; } public void setPreload_size(int preload_size) { this.preload_size = preload_size; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public int getSocket_buffer() { return socket_buffer; } public void setSocket_buffer(int socket_buffer) { this.socket_buffer = socket_buffer; } public int getUser_video_proxy() { return user_video_proxy; } public void setUser_video_proxy(int user_video_proxy) { this.user_video_proxy = user_video_proxy; } public int getVheight() { return vheight; } public void setVheight(int vheight) { this.vheight = vheight; } public String getVtype() { return vtype; } public void setVtype(String vtype) { this.vtype = vtype; } public int getVwidth() { return vwidth; } public void setVwidth(int vwidth) { this.vwidth = vwidth; } } public static class Video2Bean { /** * backup_url_1 : aHR0cDovL3Y3LnBzdGF0cC5jb20vNTk0ZTZjNDZjMjliZDkxY2EwZWJhMTFkM2RlMGIxN2EvNThkZGJlMjAvdmlkZW8vbS8yMjBlNmU2MjY3Mjg4NDU0YzkwOTFjOGYyMTZlZThiOWEwMjExNDRiZjAwMDAwMDZmNTE3YjkxMTk1Lw== * bitrate : 577524 * definition : 480p * main_url : aHR0cDovL3Y2LjM2NXlnLmNvbS92aWRlby9tLzIyMGU2ZTYyNjcyODg0NTRjOTA5MWM4ZjIxNmVlOGI5YTAyMTE0NGJmMDAwMDAwNmY1MTdiOTExOTUvP0V4cGlyZXM9MTQ5MDkzMDczNiZBV1NBY2Nlc3NLZXlJZD1xaDBoOVRkY0VNb1Myb1BqN2FLWCZTaWduYXR1cmU9JTJGbEtPMld4QVVtcUtqUGo4TWw5cFpxaFNSeEklM0Q= * preload_interval : 25 * preload_max_step : 10 * preload_min_step : 5 * preload_size : 327680 * size : 6836189 * socket_buffer : 346514400 * user_video_proxy : 1 * vheight : 480 * vtype : mp4 * vwidth : 854 */ private String backup_url_1; private int bitrate; private String definition; private String main_url; private int preload_interval; private int preload_max_step; private int preload_min_step; private int preload_size; private int size; private int socket_buffer; private int user_video_proxy; private int vheight; private String vtype; private int vwidth; public String getBackup_url_1() { return backup_url_1; } public void setBackup_url_1(String backup_url_1) { this.backup_url_1 = backup_url_1; } public int getBitrate() { return bitrate; } public void setBitrate(int bitrate) { this.bitrate = bitrate; } public String getDefinition() { return definition; } public void setDefinition(String definition) { this.definition = definition; } public String getMain_url() { return main_url; } public void setMain_url(String main_url) { this.main_url = main_url; } public int getPreload_interval() { return preload_interval; } public void setPreload_interval(int preload_interval) { this.preload_interval = preload_interval; } public int getPreload_max_step() { return preload_max_step; } public void setPreload_max_step(int preload_max_step) { this.preload_max_step = preload_max_step; } public int getPreload_min_step() { return preload_min_step; } public void setPreload_min_step(int preload_min_step) { this.preload_min_step = preload_min_step; } public int getPreload_size() { return preload_size; } public void setPreload_size(int preload_size) { this.preload_size = preload_size; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public int getSocket_buffer() { return socket_buffer; } public void setSocket_buffer(int socket_buffer) { this.socket_buffer = socket_buffer; } public int getUser_video_proxy() { return user_video_proxy; } public void setUser_video_proxy(int user_video_proxy) { this.user_video_proxy = user_video_proxy; } public int getVheight() { return vheight; } public void setVheight(int vheight) { this.vheight = vheight; } public String getVtype() { return vtype; } public void setVtype(String vtype) { this.vtype = vtype; } public int getVwidth() { return vwidth; } public void setVwidth(int vwidth) { this.vwidth = vwidth; } } public static class Video3Bean { /** * backup_url_1 : aHR0cDovL3Y3LnBzdGF0cC5jb20vNzM4NTJiOTYxNDgyMzc0MDY2NWIyN2VkODZhNWVhMTEvNThkZGJlMjAvdmlkZW8vbS8yMjA0NTViMDUyMjFjYTg0MDAxOWFjZjkwZDNmZGFmZTNhZDExNDQ4ZGMwMDAwMjRkOTFkNmZkNzZhLw== * bitrate : 1274484 * definition : 720p * main_url : aHR0cDovL3YzLjM2NXlnLmNvbS83Mzg1MmI5NjE0ODIzNzQwNjY1YjI3ZWQ4NmE1ZWExMS81OGRkYmUyMC92aWRlby9tLzIyMDQ1NWIwNTIyMWNhODQwMDE5YWNmOTBkM2ZkYWZlM2FkMTE0NDhkYzAwMDAyNGQ5MWQ2ZmQ3NmEv * preload_interval : 25 * preload_max_step : 10 * preload_min_step : 5 * preload_size : 327680 * size : 14223659 * socket_buffer : 764690400 * user_video_proxy : 1 * vheight : 720 * vtype : mp4 * vwidth : 1280 */ private String backup_url_1; private int bitrate; private String definition; private String main_url; private int preload_interval; private int preload_max_step; private int preload_min_step; private int preload_size; private int size; private int socket_buffer; private int user_video_proxy; private int vheight; private String vtype; private int vwidth; public String getBackup_url_1() { return backup_url_1; } public void setBackup_url_1(String backup_url_1) { this.backup_url_1 = backup_url_1; } public int getBitrate() { return bitrate; } public void setBitrate(int bitrate) { this.bitrate = bitrate; } public String getDefinition() { return definition; } public void setDefinition(String definition) { this.definition = definition; } public String getMain_url() { return main_url; } public void setMain_url(String main_url) { this.main_url = main_url; } public int getPreload_interval() { return preload_interval; } public void setPreload_interval(int preload_interval) { this.preload_interval = preload_interval; } public int getPreload_max_step() { return preload_max_step; } public void setPreload_max_step(int preload_max_step) { this.preload_max_step = preload_max_step; } public int getPreload_min_step() { return preload_min_step; } public void setPreload_min_step(int preload_min_step) { this.preload_min_step = preload_min_step; } public int getPreload_size() { return preload_size; } public void setPreload_size(int preload_size) { this.preload_size = preload_size; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public int getSocket_buffer() { return socket_buffer; } public void setSocket_buffer(int socket_buffer) { this.socket_buffer = socket_buffer; } public int getUser_video_proxy() { return user_video_proxy; } public void setUser_video_proxy(int user_video_proxy) { this.user_video_proxy = user_video_proxy; } public int getVheight() { return vheight; } public void setVheight(int vheight) { this.vheight = vheight; } public String getVtype() { return vtype; } public void setVtype(String vtype) { this.vtype = vtype; } public int getVwidth() { return vwidth; } public void setVwidth(int vwidth) { this.vwidth = vwidth; } } } public static class BigThumbsBean { /** * img_num : 16 * img_url : https://p1.pstatp.com/origin/19cc000499f3a6986d59 * img_x_size : 160 * img_y_size : 90 * img_x_len : 1 * img_y_len : 16 */ private int img_num; private String img_url; private int img_x_size; private int img_y_size; private int img_x_len; private int img_y_len; public int getImg_num() { return img_num; } public void setImg_num(int img_num) { this.img_num = img_num; } public String getImg_url() { return img_url; } public void setImg_url(String img_url) { this.img_url = img_url; } public int getImg_x_size() { return img_x_size; } public void setImg_x_size(int img_x_size) { this.img_x_size = img_x_size; } public int getImg_y_size() { return img_y_size; } public void setImg_y_size(int img_y_size) { this.img_y_size = img_y_size; } public int getImg_x_len() { return img_x_len; } public void setImg_x_len(int img_x_len) { this.img_x_len = img_x_len; } public int getImg_y_len() { return img_y_len; } public void setImg_y_len(int img_y_len) { this.img_y_len = img_y_len; } } } }
这个类比较庞大,都是按照服务器返回的数据而对应建立的。
3.视频系列的视图以及处理器控制
3.1.最底层视图以及处理器接口
public interface IVideoArticle { interface View extends IBaseListView<Presenter> { /** * 请求数据 */ void onLoadData(); } interface Presenter extends IBasePresenter { /** * 请求数据 */ void doLoadData(String... category); /** * 再起请求数据 */ void doLoadMoreData(); /** * 设置适配器 */ void doSetAdapter(List<MultiNewsArticleDataBean> dataBeen); } }
3.2.视频系列的视图
package com.jasonjan.headnews.module.video; 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/14. */ public class VideoArticleView extends BaseListFragment<IVideoArticle.Presenter> implements IVideoArticle.View { private static final String TAG="VideoArticleView"; private String categoryId; public static VideoArticleView newInstance(String categoryId){ Bundle bundle=new Bundle(); bundle.putString(TAG,categoryId); VideoArticleView videoArticleView=new VideoArticleView(); videoArticleView.setArguments(bundle); return videoArticleView; } @Override protected void initData() { categoryId = getArguments().getString(TAG); } @Override protected void initView(View view){ super.initView(view); super.initView(view); adapter = new MultiTypeAdapter(oldItems); Register.registerVideoArticleItem(adapter); recyclerView.setAdapter(adapter); recyclerView.addOnScrollListener(new OnLoadMoreListener() { @Override public void onLoadMore() { if (canLoadMore) { canLoadMore = false; presenter.doLoadMoreData(); } } }); } @Override public void fetchData() { super.fetchData(); onLoadData(); } @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.MUlTI_NEWS, adapter); oldItems.clear(); oldItems.addAll(newItems); canLoadMore = true; } /** * API 跟新闻的一样 所以采用类似新闻的 presenter * * @param presenter */ @Override public void setPresenter(IVideoArticle.Presenter presenter) { if (null == presenter) { this.presenter = new VideoArticlePresenter(this); } } }
然后发现处理器还没有设置呢。
然后还有视图绑定也未实现(在自定义的Register中实现)
然后还有处理新老数据来刷新(在自定义的Diffback中实现)
3.3.视频系列的处理器
这个处理器可以就用新闻页面通用的一个处理器
不过我还是自己另外写了一个处理器
和新闻页面的处理器非常相似。
package com.jasonjan.headnews.module.video; import android.text.TextUtils; import com.google.gson.Gson; import com.jasonjan.headnews.bean.news.MultiNewsArticleBean; import com.jasonjan.headnews.bean.news.MultiNewsArticleDataBean; 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.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/14. */ public class VideoArticlePresenter implements IVideoArticle.Presenter{ private static final String TAG = "VideoArticlePresenter"; private IVideoArticle.View view; private String category; private String time; private Gson gson = new Gson(); private List<MultiNewsArticleDataBean> dataList = new ArrayList<>(); VideoArticlePresenter(IVideoArticle.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(IMobileVideoApi.class) .getVideoArticle(this.category, time) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.io()) .switchMap(new Function<MultiNewsArticleBean, Observable<MultiNewsArticleDataBean>>() { @Override public Observable<MultiNewsArticleDataBean> apply(@NonNull MultiNewsArticleBean multiNewsArticleBean) throws Exception { List<MultiNewsArticleDataBean> dataList = new ArrayList<>(); for (MultiNewsArticleBean.DataBean dataBean : multiNewsArticleBean.getData()) { dataList.add(gson.fromJson(dataBean.getContent(), MultiNewsArticleDataBean.class)); } return Observable.fromIterable(dataList); } }) .filter(new Predicate<MultiNewsArticleDataBean>() { @Override public boolean test(@NonNull MultiNewsArticleDataBean dataBean) throws Exception { time = dataBean.getBehot_time(); if (TextUtils.isEmpty(dataBean.getSource())) { return false; } try { // 过滤头条问答新闻 if (dataBean.getSource().contains("头条问答") || dataBean.getTag().contains("ad") || dataBean.getSource().contains("话题")) { return false; } } catch (NullPointerException e) { ErrorAction.print(e); } // 过滤重复新闻(与上次刷新的数据比较) for (MultiNewsArticleDataBean bean : dataList) { if (bean.getTitle().equals(dataBean.getTitle())) { return false; } } return true; } }) .toList() .compose(view.<List<MultiNewsArticleDataBean>>bindToLife()) .subscribe(new Consumer<List<MultiNewsArticleDataBean>>() { @Override public void accept(@NonNull List<MultiNewsArticleDataBean> list) throws Exception { doSetAdapter(list); } }, 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<MultiNewsArticleDataBean> dataBeen) { dataList.addAll(dataBeen); view.onSetAdapter(dataList); view.onHideLoading(); } @Override public void doRefresh() { if (dataList.size() != 0) { dataList.clear(); time = TimeUtil.getCurrentTimeStamp(); } doLoadData(); } @Override public void doShowNetError() { view.onHideLoading(); view.onShowNetError(); } }
3.4.视频系列文章的API请求
public interface IMobileVideoApi { /** * 获取视频标题等信息 * http://is.snssdk.com/api/news/feed/v53/?category=subv_cute&refer=1&count=20&max_behot_time=1499321562&iid=11776029171&device_id=36394312781 */ @GET("http://is.snssdk.com/api/news/feed/v62/?iid=5034850950&device_id=6096495334&refer=1&count=20&aid=13") Observable<MultiNewsArticleBean> getVideoArticle( @Query("category") String category, @Query("max_behot_time") String maxBehotTime); /** * 获取视频信息 * Api 生成较复杂 详情查看 * http://ib.365yg.com/video/urls/v/1/toutiao/mp4/视频ID?r=17位随机数&s=加密结果 */ @GET Observable<VideoContentBean> getVideoContent(@Url String url); }
可以看到,请求视频的地址和请求之前新闻的网址是一样的
而且返回数据也一样==>Observable<MultiNewsArticleBean>
当然唯一不同的应该就是这个category,
如果带了这个参数,我猜想应该返回的东西都有带有视频的图片。
3.5.然后在Register类中注入数据类型
/** * 注入视频类型 * @param adapter */ public static void registerVideoArticleItem(@NonNull MultiTypeAdapter adapter) { adapter.register(MultiNewsArticleDataBean.class, new NewsArticleVideoViewBinder()); adapter.register(LoadingBean.class, new LoadingViewBinder()); adapter.register(LoadingEndBean.class, new LoadingEndViewBinder()); }
3.6.最后再DiffCallback中加视频类型
在areItemsTheSame函数中添加Video类型。
因为类型和Multi_News一样,用这个代替也一样。
case MUlTI_NEWS: return ((MultiNewsArticleDataBean) oldList.get(oldItemPosition)).getTitle().equals( ((MultiNewsArticleDataBean) newList.get(newItemPosition)).getTitle());
在areContentsTheSame中添加这个类型。
case MUlTI_NEWS: return ((MultiNewsArticleDataBean) oldList.get(oldItemPosition)).getItem_id() == ((MultiNewsArticleDataBean) newList.get(newItemPosition)).getItem_id();
4.视图绑定类
4.1.视图绑定类的布局定义==>item_news_article_video.xml
<?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="match_parent" 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.jasonjan.headnews.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="新闻源 - 2222条评论 - 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:id="@+id/content" 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:ellipsize="end" android:maxLines="2" android:textStyle="bold" tools:text="菲总统称中国将向菲提供武器 已指示军方前往接收"/> <RelativeLayout android:layout_width="match_parent" android:layout_height="169dp" android:paddingTop="8dp"> <ImageView android:id="@+id/iv_video_image" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@color/viewBackground" tools:ignore="ContentDescription"/> <TextView android:id="@+id/tv_video_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginRight="8dp" android:background="@color/textColorPrimary" android:padding="2dp" android:textColor="@color/White" tools:text="10:34"/> </RelativeLayout> </LinearLayout> </RelativeLayout> </android.support.v7.widget.CardView>
4.2.视图效果
4.3.视图绑定类
public class NewsArticleVideoViewBinder extends ItemViewBinder<MultiNewsArticleDataBean,NewsArticleVideoViewBinder.ViewHolder> { private static final String TAG = "NewsArticleHasVideoView"; @NonNull @Override protected NewsArticleVideoViewBinder.ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { View view = inflater.inflate(R.layout.item_news_article_video, parent, false); return new ViewHolder(view); } @Override protected void onBindViewHolder(@NonNull final NewsArticleVideoViewBinder.ViewHolder holder, @NonNull final MultiNewsArticleDataBean item) { final Context context = holder.itemView.getContext(); try { if (null != item.getVideo_detail_info()) { if (null != item.getVideo_detail_info().getDetail_video_large_image()) { String image = item.getVideo_detail_info().getDetail_video_large_image().getUrl(); if (!TextUtils.isEmpty(image)) { ImageLoader.loadCenterCrop(context, image, holder.iv_video_image, R.color.viewBackground, R.mipmap.error_image); } } } else { holder.iv_video_image.setImageResource(R.mipmap.error_image); } if (null != item.getUser_info()) { String avatar_url = item.getUser_info().getAvatar_url(); if (!TextUtils.isEmpty(avatar_url)) { ImageLoader.loadCenterCrop(context, avatar_url, holder.iv_media, R.color.viewBackground); } } String tv_title = item.getTitle(); holder.tv_title.setTextSize(SettingUtil.getInstance().getTextSize()); String tv_source = item.getSource(); String tv_comment_count = item.getComment_count() + "评论"; String tv_datetime = item.getBehot_time() + ""; if (!TextUtils.isEmpty(tv_datetime)) { tv_datetime = TimeUtil.getTimeStampAgo(tv_datetime); } int video_duration = item.getVideo_duration(); String min = String.valueOf(video_duration / 60); String second = String.valueOf(video_duration % 10); if (Integer.parseInt(second) < 10) { second = "0" + second; } String tv_video_time = min + ":" + second; holder.tv_title.setText(tv_title); holder.tv_extra.setText(tv_source + " - " + tv_comment_count + " - " + tv_datetime); holder.tv_video_time.setText(tv_video_time); 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) { IntentAction.send(context, item.getTitle() + "\n" + item.getShare_url()); } 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 { // VideoContentActivity.launch(item); } }); } catch (Exception e) { ErrorAction.print(e); } } class ViewHolder extends RecyclerView.ViewHolder { private CircleImageView iv_media; private TextView tv_extra; private TextView tv_title; private ImageView iv_video_image; private TextView tv_video_time; private ImageView iv_dots; 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_video_image = itemView.findViewById(R.id.iv_video_image); this.tv_video_time = itemView.findViewById(R.id.tv_video_time); this.iv_dots = itemView.findViewById(R.id.iv_dots); } } }
这个绑定类和新闻中的页面的其中一种类型完全一样。
因为新闻页面中有3种类型,一种纯文字,一种图片,一种视频。
这里就直接用新闻中的视频的绑定类即可。
因为API也是用的新闻
可以说视频这个大类,就是从新闻中筛选出的视频类型。
通过传入的一个参数category,返回的全是视频。
5.目前效果预览
5.1.目前完成的工作
新闻的三种大类型
图片的一种大类型,这种大类型有4个分类,为全部、老照片、故事照片和摄影集。
视频采用的是新闻中的其中一种大类型,所以直接用新闻中的绑定类即可,API也一样的。
但是每种类型的评论以及详细页面还未实现。
5.2.手机真实数据预览