对于Android的一些知识点了解一点以后,对整个项目的业务逻辑进行一遍梳理。

校园新闻APP的登录注册

首先在MainActivity中设置登录和注册按钮的点击事件,用户点击后分别跳转到相关Activity中。
所有的Activity类都继承一个BaseActivity类,在BaseActivity类中定义一些抽象的方法比如:初始化布局,初始化控件,对数据的封装,事件,接口进行操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public abstract class BaseActivity extends AppCompatActivity {
public Context mContext;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
setContentView(initLayout());
initView();
initData();
}
//初始化布局
protected abstract int initLayout();
//初始化控件
protected abstract void initView();
//数据的封装,事件,接口
protected abstract void initData();

public void showToast(String msg) {
Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
}

public void showToastSync(String msg) {
Looper.prepare();
Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
Looper.loop();
}

public void navigateTo(Class cls) {
Intent in = new Intent(mContext, cls);
startActivity(in);
}

public void navigateToWithBundle(Class cls, Bundle bundle) {
Intent in = new Intent(this, cls);
in.putExtras(bundle);
startActivity(in);
}
//清空Activity栈
public void navigateToWithFlag(Class cls, int flags) {
Intent in = new Intent(mContext, cls);
in.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(in);
}

protected void insertVal(String key, String val) {
SharedPreferences sp = getSharedPreferences("sp_ttit", MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString(key, val);
editor.commit();
}

protected String findByKey(String key) {
SharedPreferences sp = getSharedPreferences("sp_ttit", MODE_PRIVATE);
return sp.getString(key, "");
}
}

在LoginActivity中发送请求,请求响应成功后进入主页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
HashMap<String, Object> params = new HashMap<String, Object>();
params.put("username", account);
params.put("password", pwd);
Api.config(ApiConfig.LOGIN, params).postRequest(this, new TtitCallback() {
@Override
public void onSuccess(final String res) {
Log.e("onSuccess", res);
Gson gson = new Gson();
LoginResponse loginResponse = gson.fromJson(res, LoginResponse.class);
Log.e("token",loginResponse.getData().getToken());
Log.e("code",loginResponse.getCode());
if (loginResponse.getCode().equals("200")) {
String token = loginResponse.getData().getToken();
insertVal("token", token);
insertVal("userid", String.valueOf(loginResponse.getData().getId()));
Log.e("token",token);
navigateToWithFlag(HomeActivity.class,
Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
showToastSync("登录成功");
} else {
showToastSync("登录失败");
}
}

@Override
public void onFailure(Exception e) {

}


});

校园新闻主页面

用户登录成功以后,跳转到HomeActivity中,HomeActivity之中添加了两个fragment,一个是新闻首页,另一个是我的信息页面。
在HomeActivity中的xml布局文件中设置一个重写的ViewPager关闭了动画滑动效果:FixedViewPager。
使用了一个开源组件FlycoTabLayout。

  • CommonTabLayout:不同于SlidingTabLayout对ViewPager依赖,它是一个不依赖ViewPager可以与其他控件自由搭配使用的TabLayout.实现底部导航
  • SlidingTabLayout: 关联ViewPager,实现新闻的分类。

底部导航的数据适配器为MyPagerAdapter
顶部到导航Tab的数据适配器为homeFragment的HomeAdapter

HomeActivity布局文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?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:tl="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:background="#ffffff"
android:orientation="vertical"
tools:context=".activity.HomeActivity">

<com.zwj.news.view.FixedViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/divider" />

<com.flyco.tablayout.CommonTabLayout
android:id="@+id/commonTabLayout"
android:layout_width="match_parent"
android:layout_height="66dp"
android:background="#ffffff"
tl:tl_iconHeight="30dp"
tl:tl_iconWidth="30dp"
tl:tl_indicator_color="#2C97DE"
tl:tl_indicator_height="0dp"
tl:tl_textSelectColor="#0025ff"
tl:tl_textUnselectColor="#454544"
tl:tl_textsize="14sp"
tl:tl_underline_color="#DDDDDD"
tl:tl_underline_height="1dp" />
</LinearLayout>

HomeActivity的Activity文件

根据底部Tab导航添加两个Fragments到HomeActivity中,并且添加viewPage相关的MyPagerAdapter。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public class HomeActivity extends BaseActivity {

private String[] mTitles = {"首页", "我的"};
private int[] mIconUnselectIds = {
R.mipmap.home_unselect, R.mipmap.collect_unselect,
R.mipmap.my_unselect};
private int[] mIconSelectIds = {
R.mipmap.home_selected, R.mipmap.collect_selected,
R.mipmap.my_selected};
private ArrayList<Fragment> mFragments = new ArrayList<>();
private ArrayList<CustomTabEntity> mTabEntities = new ArrayList<>();
private ViewPager viewPager;
private CommonTabLayout commonTabLayout;

@Override
protected int initLayout() {
return R.layout.activity_home;
}

@Override
protected void initView() {
viewPager = findViewById(R.id.viewpager);
commonTabLayout = findViewById(R.id.commonTabLayout);
}

@Override
protected void initData() {
//添加Fragment
mFragments.add(HomeFragment.newInstance());

mFragments.add(MyFragment.newInstance());
//循环添加底部table导航
for (int i = 0; i < mTitles.length; i++) {
mTabEntities.add(new TabEntity(mTitles[i], mIconSelectIds[i], mIconUnselectIds[i]));
}
commonTabLayout.setTabData(mTabEntities);
//添加事件
commonTabLayout.setOnTabSelectListener(new OnTabSelectListener() {
//点击底部按钮,viewpager切换
@Override
public void onTabSelect(int position) {
viewPager.setCurrentItem(position);
}

@Override
public void onTabReselect(int position) {
}
});
//设置预加载
viewPager.setOffscreenPageLimit(mFragments.size());
//切换table选项的事件
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

}

@Override
public void onPageSelected(int position) {
commonTabLayout.setCurrentTab(position);
}

@Override
public void onPageScrollStateChanged(int state) {

}
});
viewPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager(), mTitles, mFragments));
}
}

底部导航的Adapter文件

主要实现底部导航切换viewPage的adapter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class MyPagerAdapter extends FragmentPagerAdapter {

private String[] mTitles;
private ArrayList<Fragment> mFragments;

public MyPagerAdapter(FragmentManager fm, String[] titles, ArrayList<Fragment> fragments) {
super(fm);
this.mTitles = titles;
this.mFragments = fragments;
}

@Override
public int getCount() {
return mFragments.size();
}

@Override
public CharSequence getPageTitle(int position) {
return mTitles[position];
}

@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
}

HomeFragment的Fragment

在HomeFragment中实现新闻分类的功能,一个viewpage就是一个分类新闻。向后端发送请求,根据获得的分类id创建新闻分类的数组。viewPage动态的添加新闻的Fragment。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
private void getVideoCategoryList() {
HashMap<String, Object> params = new HashMap<>();
Api.config(ApiConfig.News_CATEGORY_LIST, params).getRequest(getActivity(), new TtitCallback() {
@Override
public void onSuccess(final String res) {
Log.e("News_CATEGORY_LIST",res);
//创建一个新的线程,在新的线程中
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
CategoryListResponse response = new Gson().fromJson(res, CategoryListResponse.class);
if (response != null && response.getCode().equals("200")) {
List<CategoryEntity> list = response.getData();
if (list != null && list.size() > 0) {
//创建新闻分类的数组
mTitles = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
mTitles[i] = list.get(i).getType();
mFragments.add(NewsFragment.newInstance(list.get(i).getId()));
}
//设置viewPager的预加载
viewPager.setOffscreenPageLimit(mFragments.size());
viewPager.setAdapter(new HomeAdapter(getFragmentManager(), mTitles, mFragments));
slidingTabLayout.setViewPager(viewPager);
}
}
}
});
}


@Override
public void onFailure(Exception e) {
}
});
}

HomeFragment的Adapter

主要实现主页面新闻分类的viewPage的数据适配器

Fragment 与 FragmentPagerAdapter 基础篇——View和ViewGroup的区别

FragmentPagerAdapter是PagerAdapter中的其中一种实现。它将每一个页面表示为一个 Fragment,并且每一个Fragment都将会保存到fragment manager当中。而且,当用户没可能再次回到页面的时候,fragment manager才会将这个Fragment销毁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class HomeAdapter extends FragmentPagerAdapter {

private String[] mTitles;
private ArrayList<Fragment> mFragments;

public HomeAdapter(FragmentManager fm, String[] titles, ArrayList<Fragment> fragments) {
super(fm);
this.mTitles = titles;
this.mFragments = fragments;
}

@Override
public int getCount() {
return mFragments.size();
}

@Override
public CharSequence getPageTitle(int position) {
return mTitles[position];
}

@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
}

HomeFragment的布局文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tl="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:background="@color/white"
android:orientation="vertical"
tools:context=".fragment.HomeFragment">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="115dp"
android:background="#344261"
android:orientation="vertical">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="39dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="26dp"
android:layout_marginRight="24dp"
android:background="@drawable/shape_search_box"
android:gravity="center_vertical"
android:orientation="horizontal">

<ImageView
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_marginLeft="13dp"
android:src="@mipmap/search" />

<EditText
android:id="@+id/et_search"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="11dp"
android:background="@null"
android:hint="搜索新闻"
android:textColor="@color/black"
android:textColorHint="#737373"
android:textSize="15sp" />

</LinearLayout>

<com.flyco.tablayout.SlidingTabLayout
android:id="@+id/slidingTabLayout"
android:layout_width="match_parent"
android:layout_height="50dp"
tl:tl_indicator_corner_radius="1.5dp"
tl:tl_indicator_height="3dp"
tl:tl_indicator_width="17dp"
tl:tl_textSelectColor="#fdf299"
tl:tl_textUnselectColor="#ffffff"
tl:tl_indicator_color="#fdf299"
tl:tl_textsize="16sp" />

</LinearLayout>

<com.zwj.news.view.FixedViewPager
android:id="@+id/fixedViewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />

</LinearLayout>

2022-04-26_102208.png

校园新闻页面的展示

HomeActivity之中的homeFragment根据分类id添加的viewPage

NewsFragment布局文件

2.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<com.scwang.smart.refresh.layout.SmartRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical"
app:srlEnableOverScrollDrag="false"
app:srlEnableAutoLoadMore="false"
app:srlEnableOverScrollBounce="false"
app:srlEnableLoadMoreWhenContentNotFull="false"
app:srlEnablePreviewInEditMode="true"
tools:context=".fragment.NewsFragment">
<com.scwang.smart.refresh.header.ClassicsHeader
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.scwang.smart.refresh.footer.ClassicsFooter
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

</com.scwang.smart.refresh.layout.SmartRefreshLayout>

NewsFragment

RecyclerView及其子view的具体绘制工作是通过具体的LayoutManager中的onLayoutChildren和setMeasuredDimension实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
public class NewsFragment extends BaseFragment {
private int categoryId;
private String title;
private RecyclerView recyclerView;
private NewsAdapter newsAdapter;
private List<NewsEntity> datas = new ArrayList<>();
private LinearLayoutManager linearLayoutManager;
private RefreshLayout refreshLayout;
private int pageNum = 1;

public NewsFragment() {

}

//Handler:异步通信,线程之间的通信
private Handler mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
newsAdapter.setDatas(datas);
newsAdapter.notifyDataSetChanged();
recyclerView.setAdapter(newsAdapter);
break;
}
}
};

//传递新闻分类id
public static NewsFragment newInstance(int categoryId) {
NewsFragment fragment = new NewsFragment();
fragment.categoryId = categoryId;
return fragment;
}


@Override
protected int initLayout() {
return R.layout.fragment_video;
}

@Override
protected void initView() {
recyclerView = mRootView.findViewById(R.id.recyclerView);
refreshLayout = mRootView.findViewById(R.id.refreshLayout);
}

@Override
protected void initData() {
linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(linearLayoutManager);
newsAdapter = new NewsAdapter(getActivity());
recyclerView.setAdapter(newsAdapter);
//点击列表
newsAdapter.setOnItemClickListener(new NewsAdapter.OnItemClickListener() {
@Override
public void onItemClick(Serializable obj) {
Log.e("点击", "点击");
NewsEntity newsEntity = (NewsEntity) obj;
String url = "http://47.116.21.234/newsDetail?newsid=" + ((NewsEntity) obj).getId() + "&userid=" + findByKey("userid");
Log.e("url", url);
// String url="www.baidu.com";
Bundle bundle = new Bundle();
bundle.putString("url", url);
navigateToWithBundle(WebActivity.class, bundle);
}
});
//刷新
refreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(@NonNull RefreshLayout refreshLayout) {

pageNum = 1;
getVideoList(true);
Log.e("刷新", pageNum + "");

}
});
//下拉
refreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
@Override
public void onLoadMore(@NonNull RefreshLayout refreshlayout) {
pageNum++;
getVideoList(false);
Log.e("加载", pageNum + "");
}
});
getVideoList(true);
}

private void getVideoList(final Boolean isRefresh) {
String token = findByKey("token");
if (!StringUtils.isEmpty(token)) {
HashMap<String, Object> params = new HashMap<>();
// params.put("token", token);
params.put("pageNum", pageNum);
params.put("pageSize", ApiConfig.PAGE_SIZE);
params.put("title", "");
params.put("categoryId", categoryId);
Api.config(ApiConfig.News_LIST_BY_CATEGORY, params).getRequest(getActivity(), new TtitCallback() {
@Override
public void onSuccess(final String res) {
if (isRefresh) {
refreshLayout.finishRefresh(true);
} else {
refreshLayout.finishLoadMore(true);
}
NewsListResponse response = new Gson().fromJson(res, NewsListResponse.class);
if (response != null && response.getCode().equals("200")) {

List<NewsEntity> list = response.getData().getRecords();
if (list != null && list.size() > 0) {
if (isRefresh) {
datas = list;
} else {
datas.addAll(list);
}

mHandler.sendEmptyMessage(0);
} else {
if (isRefresh) {
Log.e("暂时无数据", "暂时无数据");
showToastSync("暂时无数据");
} else {
Log.e("没有更多数据了", "没有更多数据了");
showToastSync("没有更多数据了");
}
}
//
}
//
}

@Override
public void onFailure(Exception e) {
if (isRefresh) {
refreshLayout.finishRefresh(true);
} else {
refreshLayout.finishLoadMore(true);
}
}
});
} else {
navigateTo(LoginActivity.class);
}

}
}

NewsFragment的数据适配器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
public class NewsAdapter extends RecyclerView.Adapter<ViewHolder> {

private Context mContext;
private List<NewsEntity> datas;
private static OnItemClickListener mOnItemClickListener;

public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
mOnItemClickListener = onItemClickListener;
}
public NewsAdapter(Context mContext) {
this.mContext = mContext;
}

public void setDatas(List<NewsEntity> datas) {
this.datas = datas;
}

public NewsAdapter(Context context, List<NewsEntity> datas) {
this.mContext = context;
this.datas = datas;
}

@NonNull
@Override
//根据view的类型去创建不同item的viewHolder
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.item_video_layout, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
//给控件赋值
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
ViewHolder vh = (ViewHolder) holder;
NewsEntity newsEntity = datas.get(position);
vh.tvTitle.setText(newsEntity.getTitle());
vh.tvAuthor.setText(newsEntity.getUser().getNickname());

vh.newsEntity=newsEntity;

Picasso.with(mContext).load(newsEntity.getCoverimg()).placeholder(R.mipmap.load).error(R.mipmap.bad).into(vh.imageViewCover);
Picasso.with(mContext).load(newsEntity.getUser().getAvatarUrl()).transform(new CircleTransform()).placeholder(R.mipmap.header).error(R.mipmap.header).into(vh.imageViewHeard);
}

@Override
public int getItemCount () {
if (datas != null && datas.size() > 0) {
return datas.size();
} else {
return 0;
}
}

public Context getmContext() {
return mContext;
}

public List<NewsEntity> getDatas() {
return datas;
}

static class ViewHolder extends RecyclerView.ViewHolder {
private TextView tvTitle;
private TextView tvAuthor;
private TextView tvDz;
private TextView tvComment;
private TextView tvCollect;
private ImageView imageViewCover;
private ImageView imageViewHeard;
private NewsEntity newsEntity;
private ImageView imgCollect;
private ImageView imageDZ;

public ViewHolder(@NonNull View view) {
super(view);
tvTitle = view.findViewById(R.id.title);
tvAuthor = view.findViewById(R.id.author);

imageViewCover=view.findViewById(R.id.img_cover);
imageViewHeard=view.findViewById(R.id.img_header);
imgCollect=view.findViewById(R.id.img_collect);

//通过tag将ViewHolder和itemView绑定
view.setTag(this);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mOnItemClickListener.onItemClick(newsEntity);
}
});
}


}

public interface OnItemClickListener {
void onItemClick(Serializable obj);
}

}

NewsFragment的item布局文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="21dp"
android:paddingTop="13dp"
android:paddingRight="21dp">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="42dp"
android:orientation="horizontal">

<ImageView
android:id="@+id/img_header"
android:layout_width="42dp"
android:layout_height="42dp"
android:src="@mipmap/header" />

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="11dp">

<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:text="韭菜盒子新做法,不发面不烫面"
android:textColor="#242424"
android:textSize="14sp" />

<TextView
android:id="@+id/author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="大胃王"
android:textColor="#9f9f9f"
android:textSize="12sp" />

</RelativeLayout>

</LinearLayout>

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="187dp"
android:layout_marginTop="8dp">

<ImageView
android:id="@+id/img_cover"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@mipmap/default_bg" />

</RelativeLayout>

<!-- <FrameLayout-->
<!-- android:id="@+id/player_container"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="187dp"-->
<!-- android:layout_marginTop="8dp"-->
<!-- android:background="@android:color/black"-->
<!-- app:layout_constraintDimensionRatio="16:9"-->
<!-- app:layout_constraintTop_toTopOf="parent">-->

<!--&lt;!&ndash; <com.dueeeke.videocontroller.component.PrepareView&ndash;&gt;-->
<!--&lt;!&ndash; android:id="@+id/prepare_view"&ndash;&gt;-->
<!--&lt;!&ndash; android:layout_width="match_parent"&ndash;&gt;-->
<!--&lt;!&ndash; android:layout_height="match_parent" />&ndash;&gt;-->

<!-- </FrameLayout>-->

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="39dp">

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:orientation="horizontal">

<ImageView
android:id="@+id/img_comment"
android:layout_width="19dp"
android:layout_height="19dp"
android:src="@mipmap/comment" />

</LinearLayout>


</RelativeLayout>
</LinearLayout>

<View
android:layout_width="match_parent"
android:layout_height="7dp"
android:background="#f5f5f4" />
</LinearLayout>

3.png