枫叶「零碎记录」

一起撸一波干货集中营练练手Android(三)布局+实现篇

字数统计: 1.5k阅读时长: 7 min
2016/08/19 Share

整个App到了这里就开始准备开始实现逻辑啦,有没有点小期待
后续如果有需要可以爬一波包包通缉令的数据O(∩_∩)O~~

我们的布局采用5.0之后的新布局控件

1.CardView

CardView 对这个控件还不太了解的可以戳这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
CardView特别的属性如下:
android:cardCornerRadius:在布局中设置card圆角的大小
CardView.setRadius:在代码中设置card圆角的大小
android:cardBackgroundColor:在布局中设置card背景的颜色
android:elevation:设置阴影的大小
card_view:cardElevation 阴影的大小
card_view:cardMaxElevation 阴影最大高度
card_view:cardCornerRadius 卡片的圆角大小
card_view:contentPadding 卡片内容于边距的间隔
card_view:contentPaddingBottom
card_view:contentPaddingTop
card_view:contentPaddingLeft
card_view:contentPaddingRight
card_view:contentPaddingStart
card_view:contentPaddingEnd
card_view:cardUseCompatPadding 设置内边距,V21+的版本和之前的版本仍旧具有一样的计算方式
**card_view:cardPreventConrerOverlap
在V20和之前的版本中添加内边距,这个属性为了防止内容和边角的重叠**
  • 我们要使用这个CardView来做卡片式的列表
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
<android.support.v7.widget.CardView 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:layout_margin="5dp"
android:foreground="?android:attr/selectableItemBackground"
android:orientation="vertical"
app:contentPadding="5dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@id/tv_title"
style="@style/txt_normal_style"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:ellipsize="end"
android:gravity="start"
android:maxLines="3"
android:text="标题"
android:textSize="16sp"
/>
<TextView
android:id="@id/tv_name"
style="@style/txt_normal_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_below="@id/tv_title"
android:layout_marginTop="10dp"
android:gravity="bottom"
android:text="作者"
android:textColor="@color/colorPrimary"/>
<TextView
android:id="@id/tv_publishtime"
style="@style/txt_normal_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_below="@id/tv_title"
android:layout_marginTop="10dp"
android:gravity="bottom"
android:text="发表时间"/>
</RelativeLayout>
</android.support.v7.widget.CardView>

CardView 大部分适用于 listView 或者recyclerView的item中。

2.RecyclerView

RecyclerView 可以戳这里了解一下

RecyclerView与ListView原理是类似的:都是仅仅维护少量的View并且可以展示大量的数据集。RecyclerView用以下两种方式简化了数据的展示和处理:

  • 使用LayoutManager来确定每一个item的排列方式。
  • 为增加和删除项目提供默认的动画效果。

    你也可以定义你自己的LayoutManager和添加删除动画,SDK中默认包含了三种布局

    1. 横向布局(LinearLayoutManager)
    2. Grid布局(GridLayoutManager)
    3. 瀑布流布局(StaggeredGridLayoutManager)
  • Adapter:使用RecyclerView之前,你需要一个继承自RecyclerView.Adapter的适配器,作用是将数据与每一个item的界面进行绑定。
  • LayoutManager:用来确定每一个item如何进行排列摆放,何时展示和隐藏。回收或重用一个View的时候,
    LayoutManager会向适配器请求新的数据来替换旧的数据,这种机制避免了创建过多的View和频繁的调用findViewById方法(与ListView原理类似)。

总而言之就相当于ListView封装后再抽象,使item更加灵活

1
项目中我使用的是XRecyclerView,是封装了上拉刷新和下拉加载的一个库,非常好用还有挺多的加载动画可以切换,使用的方法也很简单,哈哈,偷懒!! 不都是说为了不要重复造轮子嘛~你懂的

3.Fragment

这个应该不用多讲了相信大家都会的

4.代码附上

MainFragment.java 这个就是为了在主页将一些数据初始化为了给TypeFragment拿到类型数据

  • 为什么使用FragmentStateAdapter而不用FragmentPagerAdapter是因为viewpager页数比较多
    FragmentStateAdatper的机制是空置的时候将其销毁释放内存,而FragmentPagerAdapter是将其dettach
    因此选用FragmentSteteAdapter
    

GankViewPagerAdapter.java

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 GankViewPagerAdapter extends FragmentStatePagerAdapter {
private List<Fragment> mFragments;
private List<String> mTitles;
public GankViewPagerAdapter(FragmentManager fm, List<Fragment> fragments, List<String> titles) {
super(fm);
this.mFragments = fragments;
this.mTitles = titles;
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
@Override
public int getCount() {
return mFragments.size();
}
@Override
public CharSequence getPageTitle(int position) {
return mTitles.get(position);
}
}

大家如果之前理解过MVP架构应该就会发现我调用的方式啦!

TypeFragment.java 核心模块

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
public class TypeFragment extends BaseMvpFragment<TypeFragmentView, TypePresenter> implements
TypeFragmentView {
private static final String ARG_PARAM1 = "type";
@BindView(R.id.rv_list)
XRecyclerView rvList;
private String mCategory;
private View rootView;
private GankTypeCardAdapter mGankTypeCardAdapter;
private List<GankDataEntity> mDatas;
private int curPage = 1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mCategory = getArguments().getString(ARG_PARAM1);
}
initVariables();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_type, container, false);
ButterKnife.bind(this, rootView);
resetDatas();
initViews();
return rootView;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(ARG_PARAM1, mCategory);
}
@Override
public void onViewStateRestored(Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if (savedInstanceState != null) {
mCategory = ConvertUtil.toString(savedInstanceState.getString(ARG_PARAM1), "");//避免为NULL
}
}
@Override
public void initVariables() {
mDatas = new ArrayList<>();
}
@Override
public void initViews() {
initRecyclerView();
presenter.getTypeGankList();
}
private void initRecyclerView() {
rvList.setPullRefreshEnabled(true);
rvList.setLoadingMoreEnabled(true);
rvList.setLoadingListener(new XRecyclerView.LoadingListener() {
@Override
public void onRefresh() {
resetDatas();
presenter.getTypeGankList();
}
@Override
public void onLoadMore() {
presenter.getTypeGankList();
}
});
}
@Override
protected TypePresenter initPresenter() {
return new TypePresenter();
}
public static TypeFragment newInstance(String type) {
TypeFragment fragment = new TypeFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, type);
fragment.setArguments(args);
return fragment;
}
@Override
public String getCategory() {
return mCategory;
}
@Override
public int getCurPage() {
return curPage;
}
@Override
public void addOnePage() {
curPage++;
}
@Override
public void makeUpDatas(List<GankDataEntity> datas) {
mDatas.addAll(datas);
}
@Override
public void notifyAdapter() {
if (mGankTypeCardAdapter == null) {
mGankTypeCardAdapter = new GankTypeCardAdapter(mActivity, mDatas);
rvList.setLayoutManager(new LinearLayoutManager(mActivity));
rvList.setAdapter(mGankTypeCardAdapter);
}
// TODO: 16/8/19 //此处可以优化成动画效果以及item逐个优化不需要整个重新排列
mGankTypeCardAdapter.notifyDataSetChanged();
rvList.refreshComplete();
rvList.loadMoreComplete();
}
@Override
public void resetDatas() {
curPage = 1;
mDatas.clear();
if (mGankTypeCardAdapter != null) {
mGankTypeCardAdapter.notifyDataSetChanged();
}
}
@Override
public void onDestroyView() {
mGankTypeCardAdapter = null;
super.onDestroyView();
}
}

最后就是P中调用V啦 就是传说中的解耦


到此基本上的请求列表功能结束啦,下一篇最终章就是列表点击事件和链接的内容页面!

有问题可以来我博客或者简书反馈,谢谢大家的停留在这里时间

附上源码下载地址

CATALOG
  1. 1. 1.CardView
  2. 2. 2.RecyclerView
  3. 3. 3.Fragment
  4. 4. 4.代码附上