博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[Android学习笔记三] Support v7提供交错式网格布局开发示例
阅读量:6762 次
发布时间:2019-06-26

本文共 12316 字,大约阅读时间需要 41 分钟。

   本文主要介绍Android Support v7提供的RecycleView和交错式布局(通常成为瀑布流布局)的使用和事件监听处理。

  1. 涉及到开源库有:

    : 

   Facebook开源的不是一般强大的图片加载组件库 

    : 

   Android View和事件绑定库,通过注解完成,在编译时APT处理注解文档。

  

  2. 模块配置

    

   Android Studio模块,build.gradle配置:

   

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
apply plugin: 
'com.android.application'
android {
    
compileSdkVersion 
21
    
buildToolsVersion 
'21.1.2'
 
    
defaultConfig {
        
applicationId 
'secondriver.sdk'
        
minSdkVersion 
16
        
targetSdkVersion 
21
        
versionCode 
1
        
versionName 
'1.0'
    
}
    
buildTypes {
        
release {
            
minifyEnabled false
            
proguardFiles getDefaultProguardFile(
'proguard-android.txt'
), 
'proguard-rules.pro'
        
}
    
}
 
    
packagingOptions {
        
exclude 
'META-INF/services/javax.annotation.processing.Processor'
    
}
 
    
lintOptions {
        
disable 
'InvalidPackage'
    
}
}
dependencies {
    
compile fileTree(dir: 
'libs'
, include: [
'*.jar'
])
 
    
compile 
'com.android.support:appcompat-v7:21.0.3'
    
compile 
'com.android.support:recyclerview-v7:21.0.3@aar'
    
compile 
'com.android.support:cardview-v7:21.0.3@aar'
 
    
compile 
'com.facebook.fresco:fresco:0.8.0'
    
compile 
'com.jakewharton:butterknife:7.0.1'
 
    
testCompile 
'junit:junit:4.12'
}

   3. 布局文件

    主布局文件:activity_recycleview.xml 包含一个RecycleView,将作为主屏幕组件。

   

1
2
3
4
5
6
7
8
9
10
11
12
13
<?
xml 
version
=
"1.0" 
encoding
=
"utf-8"
?>
<
RelativeLayout 
android:id
=
"@+id/swipe_refresh_layout"
                
xmlns:android
=
"http://schemas.android.com/apk/res/android"
                
android:layout_width
=
"match_parent"
                
android:layout_height
=
"wrap_content"
>
    
<
android.support.v7.widget.RecyclerView
        
android:id
=
"@+id/recycler_view"
        
android:layout_width
=
"match_parent"
        
android:layout_height
=
"wrap_content"
        
android:layout_alignParentTop
=
"true"
        
android:scrollbars
=
"vertical"
        
/>
</
RelativeLayout
>

    RecycleView 通过设置不同的布局管理器对象来实现不同的布局显示,如:   

    android.support.v7.widget.LinearLayoutManager 可以实现ListView的布局效果

    android.support.v7.widget.GridLayoutManager  可以实现GridView的布局效果

    android.support.v7.widget.StaggeredGridLayoutManager 可以实现交错式网格布局效果

    次布局文件(RecycleView中显示的每一项视图的布局):item_recycelview.xml 通过com.android.support:CardView包提供的CardView帧式容器布局包含一个ImageView和TextView作为RecycleView的每一项视图的布局。

    

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
<?
xml 
version
=
"1.0" 
encoding
=
"utf-8"
?>
<
LinearLayout 
xmlns:android
=
"http://schemas.android.com/apk/res/android"
              
xmlns:card_view
=
"http://schemas.android.com/apk/res-auto"
              
xmlns:fresco
=
"http://schemas.android.com/tools"
              
android:layout_width
=
"match_parent" 
android:layout_height
=
"match_parent"
              
android:gravity
=
"center"
>
 
    
<
android.support.v7.widget.CardView
        
android:id
=
"@+id/card_view"
        
android:layout_width
=
"wrap_content"
        
android:layout_height
=
"wrap_content"
        
android:layout_gravity
=
"center"
        
card_view:cardCornerRadius
=
"4dp"
        
card_view:cardUseCompatPadding
=
"true"
>
 
        
<
RelativeLayout
            
android:layout_width
=
"match_parent"
            
android:layout_height
=
"wrap_content" 
android:orientation
=
"vertical"
>
 
            
<
com.facebook.drawee.view.SimpleDraweeView
                
android:id
=
"@+id/info_image"
                
android:layout_width
=
"300dp"
                
android:layout_height
=
"420dp"
                
fresco:actualImageScaleType
=
"centerCrop"
                
fresco:placeholderImage
=
"@mipmap/ic_launcher"
                
fresco:roundAsCircle
=
"false"
                
fresco:roundBottomLeft
=
"true"
                
fresco:roundBottomRight
=
"true"
                
fresco:roundTopLeft
=
"true"
                
fresco:roundTopRight
=
"true"
                
fresco:roundedCornerRadius
=
"1dp"
                
fresco:roundingBorderWidth
=
"2dp"
                
/>
            
<
TextView
                
android:id
=
"@+id/info_text"
                
android:layout_width
=
"200dp"
                
android:layout_height
=
"80dp"
                
android:textSize
=
"20sp"
                
android:textColor
=
"@android:color/holo_blue_dark"
                
android:textAppearance
=
"?android:attr/textAppearanceMedium"
                
android:layout_alignLeft
=
"@id/info_image"
                
android:layout_alignRight
=
"@id/info_image"
                
android:layout_below
=
"@id/info_image"
                
android:gravity
=
"left|center_vertical"
/>
        
</
RelativeLayout
>
    
</
android.support.v7.widget.CardView
>
</
LinearLayout
>

    

    ImageView组件使用的是Fresco库提供的视图组件。

 4. Activity实现和数据填充

    4.1 RecycleView中的每一项视图的数据组成

       文本信息+ 图片地址(url,file,resId) 本示例中采用Url网络图片

       

1
2
3
4
5
6
7
8
9
10
11
12
/**
     
* View项的数据对象
     
*/
    
static 
class 
Pair {
        
public 
String text;
        
public 
String url;
 
        
public 
Pair(String text, String url) {
            
this
.text = text;
            
this
.url = url;
        
}
    
}

        

   

    4.2 RecycleView中国的每一项视图的数据填充,即适配器

        自定义适配器需要实现RecycleView.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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
static 
class 
RecycleViewAdapter 
extends 
RecyclerView.Adapter<RecyclerView.ViewHolder> {
 
        
/**
         
* RecycleView的View项单击事件监听
         
*/
        
public 
interface 
OnRecycleViewItemClickListener {
 
            
void 
onRecycleViewItemClick(View view, 
int 
position);
        
}
 
        
private 
ArrayList<Pair> items = 
new 
ArrayList<>();
 
        
private 
OnRecycleViewItemClickListener mOnRecycleViewItemClickListener;
 
        
public 
RecycleViewAdapter(ArrayList<Pair> items) {
            
this
.items = items;
        
}
 
        
@Override
        
public 
RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, 
int 
viewType) {
            
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recyclerview, parent, 
false
);
            
return 
new 
RecycleViewItemHolder(view, mOnRecycleViewItemClickListener);
        
}
 
        
@Override
        
public 
void 
onBindViewHolder(RecyclerView.ViewHolder holder, 
int 
position) {
            
Pair pair = items.get(position);
            
((RecycleViewItemHolder) holder).setContent(pair);
        
}
 
        
@Override
        
public 
int 
getItemCount() {
            
return 
items.size();
        
}
 
        
public 
void 
setOnRecycleViewItemClickListener(OnRecycleViewItemClickListener onItemClickListener) {
            
if 
(
null 
!= onItemClickListener) {
                
this
.mOnRecycleViewItemClickListener = onItemClickListener;
            
}
        
}
    
}

   主要实现onCreateViewHolder和onBindViewHolder方法。由于RecycleView并未提供为视图项添加监听事件,这里自定义个一个事件监听接口,在实例化适配器的时候可以选择设置事件监听。

   4.3 创建ViewHolder需要通过自定义ViewHolder类继承RecycleView.ViewHolder。

  

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
static 
class 
RecycleViewItemHolder 
extends 
RecyclerView.ViewHolder 
implements 
View.OnClickListener {
 
        
@Bind
(R.id.info_text)
        
public 
TextView infoTextView;
 
        
@Bind
(R.id.info_image)
        
public 
SimpleDraweeView draweeView;
 
        
private 
RecycleViewAdapter.OnRecycleViewItemClickListener onItemClickListener;
 
        
public 
RecycleViewItemHolder(View itemView, RecycleViewAdapter.OnRecycleViewItemClickListener onItemClickListener) {
            
super
(itemView);
            
ButterKnife.bind(
this
, itemView);
            
this
.onItemClickListener = onItemClickListener;
            
itemView.setOnClickListener(
this
);
        
}
 
        
public 
void 
setContent(Pair pair) {
            
infoTextView.setText(pair.text);
            
draweeView.setImageURI(Uri.parse(pair.url));
        
}
 
        
@Override
        
public 
void 
onClick(View v) {
            
if 
(
null 
!= onItemClickListener) {
                
onItemClickListener.onRecycleViewItemClick(v, getPosition());
            
}
        
}
    
}

    在构造方法中的传入OnRecycleViewItemClickListener对象,并且自定义ViewHolder实现OnClickListener接口,通过为itemView对象设置OnClickListener监听事件,在onClick方法中将点击事件的处理交由OnRecycleViewItemClickListener对象处理,从而达到为RecycleView中的itemView注册点击事件。

    如果不采用这种方式添加事件监听,就不需要自定义监听接口和自定义ViewHolder实现事件监听接口以及事件处理。另外可以通过获得的itemView之后,通过组件I的获取组件来添加事件监听。还可以通过获得的自定义ViewHolder,来访问每个组件。

   4.4 Activity的具体实现

    

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
151
152
153
154
155
156
157
package 
secondriver.sdk.activity;
 
import 
android.app.Activity;
import 
android.net.Uri;
import 
android.os.Bundle;
import 
android.support.v7.widget.DefaultItemAnimator;
import 
android.support.v7.widget.RecyclerView;
import 
android.support.v7.widget.StaggeredGridLayoutManager;
import 
android.util.Log;
import 
android.view.LayoutInflater;
import 
android.view.View;
import 
android.view.ViewGroup;
import 
android.widget.TextView;
import 
android.widget.Toast;
 
import 
com.facebook.drawee.view.SimpleDraweeView;
 
import 
java.util.ArrayList;
import 
java.util.Arrays;
import 
java.util.Random;
 
import 
butterknife.Bind;
import 
butterknife.ButterKnife;
import 
secondriver.sdk.R;
 
/**
 
* Author : secondriver
 
* Created : 2015/11/18
 
*/
public 
class 
RecycleViewActivity 
extends 
Activity {
 
    
private 
static 
final 
String TAG = RecyclerView.
class
.getName();
 
    
private 
static 
final 
String[] RES_URL = 
new 
String[]{
            
"http://p1.wmpic.me/article/2015/11/16/1447644849_hySANEEF.jpg"
,
            
//减少篇幅,此处省去14个图片Url
    
};
 
    
@Bind
(R.id.recycler_view)
    
public 
RecyclerView mRecycleView;
 
    
private 
final 
int 
PRE_SCREEN_NUMBER = 
6
;
    
private 
final 
int 
SPAN_COUNT = 
2
;
 
    
private 
int 
previousLastIndex = 
0
;
    
private 
boolean 
isSlidingToLast = 
false
;
 
    
private 
RecycleViewAdapter mAdapter;
    
private 
ArrayList<Pair> mItem = 
new 
ArrayList<>();
 
    
//交错式网格布局管理对象,即通常称的瀑布流布局
    
private 
StaggeredGridLayoutManager mLayoutManager;
 
    
@Override
    
protected 
void 
onCreate(Bundle savedInstanceState) {
        
super
.onCreate(savedInstanceState);
        
setContentView(R.layout.activity_recyclerview);
        
ButterKnife.bind(
this
);
    
Fresco.initialize(
this
); 
//重要,Fresco做一系列初始化工作
        
initRecycleView();
    
}
 
    
private 
void 
initRecycleView() {
 
        
mLayoutManager = 
new 
StaggeredGridLayoutManager(SPAN_COUNT, StaggeredGridLayoutManager.VERTICAL);
        
mRecycleView.setLayoutManager(mLayoutManager);
 
        
mAdapter = 
new 
RecycleViewAdapter(mItem);
        
loadData(
false
);
 
        
mRecycleView.setAdapter(mAdapter);
        
mRecycleView.setItemAnimator(
new 
DefaultItemAnimator());
 
        
//RecycleView的View项单击事件监听
        
mAdapter.setOnRecycleViewItemClickListener(
new 
RecycleViewAdapter.OnRecycleViewItemClickListener() {
 
            
@Override
            
public 
void 
onRecycleViewItemClick(View view, 
int 
position) {
 
                
long 
id = mRecycleView.getChildItemId(view);
                
Log.d(TAG, 
"View项的根视图:" 
+ view.getClass().getName() + 
",position=" 
+ position + 
" ViewHolder_Id=" 
+ id);
 
                
//通过findViewById查找View项中的元素
                
SimpleDraweeView draweeView = (SimpleDraweeView) view.findViewById(R.id.info_image);
                
if 
(
null 
!= draweeView) {
                    
draweeView.setImageURI(Uri.parse(RES_URL[
0
]));
                    
Toast.makeText(RecycleViewActivity.
this
"通过findViewById查找View项中的元素"
, Toast.LENGTH_LONG).show();
                
}
 
                
RecycleViewItemHolder recycleViewItemHolder = (RecycleViewItemHolder) mRecycleView.findViewHolderForPosition(position);
                
if 
(
null 
!= recycleViewItemHolder) {
                    
recycleViewItemHolder.infoTextView.setText(
"通过ViewHolder找到View项中的元素"
);
                
}
            
}
        
});
 
        
//下拉刷新,追加内容
        
mRecycleView.setOnScrollListener(
                
new 
RecyclerView.OnScrollListener() {
 
                    
@Override
                    
public 
void 
onScrollStateChanged(RecyclerView recyclerView, 
int 
newState) {
                        
super
.onScrollStateChanged(recyclerView, newState);
 
                        
if 
(newState == RecyclerView.SCROLL_STATE_IDLE) {
                            
if 
(isPullToBottom() && isSlidingToLast) {
                                
if 
(mItem.size() > 
36
) { 
//最大数据量
                                    
Toast.makeText(RecycleViewActivity.
this
"没有数据了"
, Toast.LENGTH_LONG).show();
                                    
return
;
                                
else 
{
                                    
loadData(
false
);
                                    
Log.d(TAG, 
"notifyItemRangeInserted startPosition=" 
+ previousLastIndex);
                                    
mAdapter.notifyItemRangeInserted(previousLastIndex, PRE_SCREEN_NUMBER);
                                
}
                            
}
                        
}
                        
if 
(newState == RecyclerView.SCROLL_STATE_SETTLING) {
                            
Log.d(TAG, 
"settling"
);
                        
}
                    
}
 
                    
@Override
                    
public 
void 
onScrolled(RecyclerView recyclerView, 
int 
dx, 
int 
dy) {
                        
super
.onScrolled(recyclerView, dx, dy);
                        
isSlidingToLast = dy > 
0
//上拉,下滑
                        
Log.d(TAG, 
"dx = " 
+ dx + 
" dy=" 
+ dy + 
" isSlidingToLast=" 
+ isSlidingToLast);
                    
}
                
}
        
);
 
    
}
 
    
private 
boolean 
isPullToBottom() {
        
int
[] lastIndexs = mLayoutManager.findLastCompletelyVisibleItemPositions(
null
);
        
Log.d(TAG, 
"last item =" 
+ Arrays.toString(lastIndexs) + 
", have item=" 
+ mAdapter.getItemCount());
        
int 
maxIndex = mAdapter.getItemCount() - 
1
;
        
for 
(
int 
i : lastIndexs) {
            
if 
(i == maxIndex) {
                
return 
true
;
            
}
        
}
        
return 
false
;
    
}
 
 
    
private 
void 
loadData(
boolean 
isClear) {
        
if 
(isClear) {
            
mItem.clear();
        
}
        
previousLastIndex = mItem.size();
        
Random r = 
new 
Random();
        
for 
(
int 
index = 
0
; index < PRE_SCREEN_NUMBER && index < RES_URL.length; index++) {
            
mItem.add(
new 
Pair(
"Card " 
+ (previousLastIndex + index), RES_URL[r.nextInt(RES_URL.length)]));
        
}
        
Log.d(TAG, 
"mItem count =" 
+ mItem.size());
    
}
}

    说明:

    RecycleView的ItemView的数据由Pair对象管理存储

    Fresco库默认配置下的使用之前需要初始化调用Fresco.initialize(Context)

    上述实现了2个事件监听,一个OnScrollerListener由RecycleView提供,实现下拉刷新;一个OnRecycleViewItemClickListener由自定义的RecycleViewAdpater提供,实现单击itemView来更换图片(SimpleDraweeView)和文字(TextView)。

    和库的具体使用参见其Github上的文档。

 

5. 效果图

  

  比较遗憾ScreenRecord不支持模拟器和Android4.4一下的系统,只能附上截图。

  

本文转自 secondriver 51CTO博客,原文链接:http://blog.51cto.com/aiilive/1715139,如需转载请自行联系原作者
你可能感兴趣的文章
IOS 播放动态Gif图片
查看>>
随笔1
查看>>
HTML中Select的使用具体解释
查看>>
Java synchronized
查看>>
mysql大内存高性能优化方案
查看>>
VSTO 学习笔记(十二)自定义公式与Ribbon
查看>>
[再寄小读者之数学篇](2015-06-24 Series)
查看>>
【Linux】linux常用基本命令
查看>>
4-python学习——数据操作
查看>>
Oracle函数
查看>>
Unity3D学习笔记第一课
查看>>
【redis使用全解析】常见运维操作
查看>>
hdu2377Bus Pass(构建更复杂的图+spfa)
查看>>
Vc6.0打开该文件坠毁
查看>>
[LeetCode] Lowest Common Ancestor of a Binary Search Tree 二叉搜索树的最小共同父节点
查看>>
2015第29周三
查看>>
hdu5024(dp)
查看>>
算法-无向图(连通分量,是否有环和二分图)
查看>>
IOS runtime动态运行时一
查看>>
媒体播放器三大底层架构
查看>>