对于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); } 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() { mFragments.add(HomeFragment.newInstance());
mFragments.add(MyFragment.newInstance()); 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() { @Override public void onTabSelect(int position) { viewPager.setCurrentItem(position); }
@Override public void onTabReselect(int position) { } }); viewPager.setOffscreenPageLimit(mFragments.size()); 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.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>
|

校园新闻页面的展示
HomeActivity之中的homeFragment根据分类id添加的viewPage
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
| <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() {
}
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; } } };
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); 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("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 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);
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>
<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>
|
