开始逐渐领略到ItemDecoration的美~
今天让我 使用 ItemDecoration 来完成 可推动的悬浮导航栏的效果,最终实现的效果如下图:
具体实现步骤如下:
根据我前面的文章所讲的RecyclerView的基本使用,我们先来完成基本的recyclerView:
第一步:布局里写一个RecyclerView
第二步:实例化
1
|
recyclerView
=
(
RecyclerView
)
findViewById
(
R
.
id
.
recyclerView
)
;
|
第三步:获取所需的数据 (这里我们来个真实点的情景,去联网请求数据)
1
2
3
4
|
/**
* 联网请求所需的url
*/
public
String
url
=
"http://api.meituan.com/mmdb/movie/v2/list/rt/order/coming.json?ci=1&limit=12&token=&__vhost=api.maoyan.com&utm_campaign=AmovieBmovieCD-1&movieBundleVersion=6801&utm_source=xiaomi&utm_medium=android&utm_term=6.8.0&utm_content=868030022327462&net=255&dModel=MI%205&uuid=0894DE03C76F6045D55977B6D4E32B7F3C6AAB02F9CEA042987B380EC5687C43&lat=40.100673&lng=116.378619&__skck=6a375bce8c66a0dc293860dfa83833ef&__skts=1463704714271&__skua=7e01cf8dd30a179800a7a93979b430b2&__skno=1a0b4a9b-44ec-42fc-b110-ead68bcc2824&__skcy=sXcDKbGi20CGXQPPZvhCU3%2FkzdE%3D"
;
|
1
2
|
//联网获取数据
getDataFromNet
(
)
;
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/**
* 使用okhttpUtils进行联网请求数据
*/
private
void
getDataFromNet
(
)
{
OkHttpUtils
.
get
(
)
.
url
(
url
)
.
build
(
)
.
execute
(
new
StringCallback
(
)
{
@Override
public
void
onError
(
okhttp3
.
Call
call
,
Exception
e
,
int
id
)
{
Log
.
e
(
"TAG"
,
"联网失败"
+
e
.
getMessage
(
)
)
;
}
@Override
public
void
onResponse
(
String
response
,
int
id
)
{
Log
.
e
(
"TAG"
,
"联网成功=="
+
response
)
;
//联网成功后使用fastjson解析
processData
(
response
)
;
}
}
)
;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
/**
* 使用fastjson进行解析
*
* @param json
*/
private
void
processData
(
String
json
)
{
//这里使用GsonFormat生成对应的bean类
JSONObject
jsonObject
=
parseObject
(
json
)
;
String
data
=
jsonObject
.
getString
(
"data"
)
;
JSONObject
dataObj
=
JSON
.
parseObject
(
data
)
;
String
coming
=
dataObj
.
getString
(
"coming"
)
;
List
<
WaitMVBean
.
DataBean
.
ComingBean
>
comingslist
=
parseArray
(
coming
,
WaitMVBean
.
DataBean
.
ComingBean
.
class
)
;
//测试是否解析数据成功
// String strTest = comingslist.get(0).getCat();
// Log.e("TAG", strTest + "222");
//解析数据成功,设置适配器-->
}
}
|
第四步:解析数据成功后,创建并设置适配器,并传递相关数据
1
2
3
|
//解析数据成功,设置适配器
MyRecyclerAdapter
adapter
=
new
MyRecyclerAdapter
(
mContext
,
comingslist
)
;
recyclerView
.
setAdapter
(
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
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
|
public
class
MyRecyclerAdapter
extends
RecyclerView
.
Adapter
{
private
final
List
<
WaitMVBean
.
DataBean
.
ComingBean
>
comingslist
;
private
final
Context
mContext
;
private
final
LayoutInflater
mLayoutInflater
;
public
MyRecyclerAdapter
(
Context
mContext
,
List
<
WaitMVBean
.
DataBean
.
ComingBean
>
comingslist
)
{
this
.
mContext
=
mContext
;
this
.
comingslist
=
comingslist
;
mLayoutInflater
=
LayoutInflater
.
from
(
mContext
)
;
}
@Override
public
RecyclerView
.
ViewHolder
onCreateViewHolder
(
ViewGroup
parent
,
int
viewType
)
{
return
new
MyViewHolder
(
mLayoutInflater
.
inflate
(
R
.
layout
.
date_item
,
null
)
)
;
}
@Override
public
void
onBindViewHolder
(
RecyclerView
.
ViewHolder
holder
,
int
position
)
{
MyViewHolder
myholder
=
(
MyViewHolder
)
holder
;
myholder
.
setData
(
position
)
;
}
@Override
public
int
getItemCount
(
)
{
return
comingslist
.
size
(
)
;
}
class
MyViewHolder
extends
RecyclerView
.
ViewHolder
{
private
TextView
mv_name
;
private
TextView
mv_dec
;
private
TextView
mv_date
;
private
ImageView
imageView
;
public
MyViewHolder
(
View
itemView
)
{
super
(
itemView
)
;
mv_name
=
(
TextView
)
itemView
.
findViewById
(
R
.
id
.
mv_name
)
;
mv_dec
=
(
TextView
)
itemView
.
findViewById
(
R
.
id
.
mv_dec
)
;
mv_date
=
(
TextView
)
itemView
.
findViewById
(
R
.
id
.
mv_date
)
;
imageView
=
(
ImageView
)
itemView
.
findViewById
(
R
.
id
.
image
)
;
}
public
void
setData
(
int
position
)
{
WaitMVBean
.
DataBean
.
ComingBean
coming
=
comingslist
.
get
(
position
)
;
String
name
=
coming
.
getNm
(
)
;
mv_name
.
setText
(
name
)
;
String
date
=
coming
.
getShowInfo
(
)
;
mv_date
.
setText
(
date
)
;
String
dec
=
coming
.
getScm
(
)
;
mv_dec
.
setText
(
dec
)
;
//注:当你发下图片无法打开是,做个字符串替换即可
String
imagUrl
=
coming
.
getImg
(
)
;
String
newImagUrl
=
imagUrl
.
replaceAll
(
"w.h"
,
"50.80"
)
;
//使用Glide加载图片
Glide
.
with
(
mContext
)
.
load
(
newImagUrl
)
.
into
(
imageView
)
;
}
}
}
|
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
|
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
LinearLayout
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
background
=
"#ffffff"
android
:
gravity
=
"center_vertical"
android
:
orientation
=
"horizontal"
>
<
ImageView
android
:
id
=
"@+id/image"
android
:
layout_width
=
"70dp"
android
:
layout_height
=
"110dp"
android
:
layout_marginBottom
=
"5dp"
android
:
layout_marginLeft
=
"10dp"
android
:
layout_marginRight
=
"8dp"
android
:
layout_marginTop
=
"5dp"
/
>
<
LinearLayout
android
:
layout_width
=
"0dp"
android
:
layout_height
=
"wrap_content"
android
:
layout_marginLeft
=
"6dp"
android
:
layout_weight
=
"1"
android
:
orientation
=
"vertical"
>
<
TextView
android
:
id
=
"@+id/mv_name"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
text
=
"神奇動物在哪裏"
android
:
textColor
=
"#000000"
android
:
textSize
=
"15sp"
/
>
<
LinearLayout
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
orientation
=
"horizontal"
>
<
TextView
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
text
=
"观众"
android
:
textColor
=
"#55000000"
android
:
textSize
=
"14sp"
/
>
<
TextView
android
:
id
=
"@+id/tv_people"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
text
=
"9.0 "
android
:
textColor
=
"#FFCE42"
android
:
textSize
=
"18sp"
/
>
<
TextView
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
text
=
" | 专业"
android
:
textColor
=
"#55000000"
android
:
textSize
=
"14sp"
/
>
<
TextView
android
:
id
=
"@+id/tv_professional"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
text
=
"6.7"
android
:
textColor
=
"#FFCE42"
android
:
textSize
=
"18sp"
/
>
<
/
LinearLayout
>
<
TextView
android
:
id
=
"@+id/mv_dec"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
layout_marginTop
=
"8dp"
android
:
text
=
"神奇動物城,法師顯超能"
android
:
textColor
=
"#99000000"
android
:
textSize
=
"11sp"
/
>
<
TextView
android
:
id
=
"@+id/mv_date"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
layout_marginTop
=
"10dp"
android
:
text
=
"今天165家影院放映2088场"
android
:
textColor
=
"#99000000"
android
:
textSize
=
"11sp"
/
>
<
/
LinearLayout
>
<
/
LinearLayout
>
|
第五步:一定不能忘!!!
recycleView不仅要设置适配器还要设置布局管理者,否则图片不显示
1
2
|
GridLayoutManager
manager
=
new
GridLayoutManager
(
this
,
1
)
;
recyclerView
.
setLayoutManager
(
manager
)
;
|
此时RecyclerView简单的完成效果如下:
下面开始做 可推动的 悬浮导航栏:
第一步:首先我们来写一个类,它起标记的作用,来放每一个item的对应的悬浮栏的字符串
1
2
3
4
5
6
7
8
9
10
11
|
public
class
NameBean
{
String
name
;
public
String
getName
(
)
{
return
name
;
}
public
void
setName
(
String
name
)
{
this
.
name
=
name
;
}
}
|
第二步:自定义一个SectionDecoration 类 继承 RecyclerView的ItemDecoration
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
|
public
class
SectionDecoration
extends
RecyclerView
.
ItemDecoration
{
private
static
final
String
TAG
=
"SectionDecoration"
;
private
List
<NameBean>
dataList
;
private
DecorationCallback
callback
;
private
TextPaint
textPaint
;
private
Paint
paint
;
private
int
topGap
;
private
int
alignBottom
;
private
Paint
.
FontMetrics
fontMetrics
;
public
SectionDecoration
(
List
<NameBean>
dataList
,
Context
context
,
DecorationCallback
decorationCallback
)
{
Resources
res
=
context
.
getResources
(
)
;
this
.
dataList
=
dataList
;
this
.
callback
=
decorationCallback
;
//设置悬浮栏的画笔---paint
paint
=
new
Paint
(
)
;
paint
.
setColor
(
res
.
getColor
(
R
.
color
.
colorGray
)
)
;
//设置悬浮栏中文本的画笔
textPaint
=
new
TextPaint
(
)
;
textPaint
.
setAntiAlias
(
true
)
;
textPaint
.
setTextSize
(
DensityUtil
.
dip2px
(
context
,
14
)
)
;
textPaint
.
setColor
(
Color
.
DKGRAY
)
;
textPaint
.
setTextAlign
(
Paint
.
Align
.
LEFT
)
;
fontMetrics
=
new
Paint
.
FontMetrics
(
)
;
//决定悬浮栏的高度等
topGap
=
res
.
getDimensionPixelSize
(
R
.
dimen
.
sectioned_top
)
;
//决定文本的显示位置等
alignBottom
=
res
.
getDimensionPixelSize
(
R
.
dimen
.
sectioned_alignBottom
)
;
}
@Override
public
void
getItemOffsets
(
Rect
outRect
,
View
view
,
RecyclerView
parent
,
RecyclerView
.
State
state
)
{
super
.
getItemOffsets
(
outRect
,
view
,
parent
,
state
)
;
int
pos
=
parent
.
getChildAdapterPosition
(
view
)
;
Log
.
i
(
TAG
,
"getItemOffsets:"
+
pos
)
;
String
groupId
=
callback
.
getGroupId
(
pos
)
;
if
(
groupId
.
equals
(
"-1"
)
)
return
;
//只有是同一组的第一个才显示悬浮栏
if
(
pos
==
0
||
isFirstInGroup
(
pos
)
)
{
outRect
.
top
=
topGap
;
if
(
dataList
.
get
(
pos
)
.
getName
(
)
==
""
)
{
outRect
.
top
=
0
;
}
}
else
{
outRect
.
top
=
0
;
}
}
@Override
public
void
onDraw
(
Canvas
c
,
RecyclerView
parent
,
RecyclerView
.
State
state
)
{
super
.
onDraw
(
c
,
parent
,
state
)
;
int
left
=
parent
.
getPaddingLeft
(
)
;
int
right
=
parent
.
getWidth
(
)
-
parent
.
getPaddingRight
(
)
;
int
childCount
=
parent
.
getChildCount
(
)
;
for
(
int
i
=
0
;
i
<
childCount
;
i
++
)
{
View
view
=
parent
.
getChildAt
(
i
)
;
int
position
=
parent
.
getChildAdapterPosition
(
view
)
;
String
groupId
=
callback
.
getGroupId
(
position
)
;
if
(
groupId
.
equals
(
"-1"
)
)
return
;
String
textLine
=
callback
.
getGroupFirstLine
(
position
)
.
toUpperCase
(
)
;
if
(
textLine
==
""
)
{
float
top
=
view
.
getTop
(
)
;
float
bottom
=
view
.
getTop
(
)
;
c
.
drawRect
(
left
,
top
,
right
,
bottom
,
paint
)
;
return
;
}
else
{
if
(
position
==
0
||
isFirstInGroup
(
position
)
)
{
float
top
=
view
.
getTop
(
)
-
topGap
;
float
bottom
=
view
.
getTop
(
)
;
//绘制悬浮栏
c
.
drawRect
(
left
,
top
-
topGap
,
right
,
bottom
,
paint
)
;
//绘制文本
c
.
drawText
(
textLine
,
left
,
bottom
,
textPaint
)
;
}
}
}
}
@Override
public
void
onDrawOver
(
Canvas
c
,
RecyclerView
parent
,
RecyclerView
.
State
state
)
{
super
.
onDrawOver
(
c
,
parent
,
state
)
;
int
itemCount
=
state
.
getItemCount
(
)
;
int
childCount
=
parent
.
getChildCount
(
)
;
int
left
=
parent
.
getPaddingLeft
(
)
;
int
right
=
parent
.
getWidth
(
)
-
parent
.
getPaddingRight
(
)
;
float
lineHeight
=
textPaint
.
getTextSize
(
)
+
fontMetrics
.
descent
;
String
preGroupId
=
""
;
String
groupId
=
"-1"
;
for
(
int
i
=
0
;
i
<
childCount
;
i
++
)
{
View
view
=
parent
.
getChildAt
(
i
)
;
int
position
=
parent
.
getChildAdapterPosition
(
view
)
;
preGroupId
=
groupId
;
groupId
=
callback
.
getGroupId
(
position
)
;
if
(
groupId
.
equals
(
"-1"
)
||
groupId
.
equals
(
preGroupId
)
)
continue
;
String
textLine
=
callback
.
getGroupFirstLine
(
position
)
.
toUpperCase
(
)
;
if
(
TextUtils
.
isEmpty
(
textLine
)
)
continue
;
int
viewBottom
=
view
.
getBottom
(
)
;
float
textY
=
Math
.
max
(
topGap
,
view
.
getTop
(
)
)
;
//下一个和当前不一样移动当前
if
(
position
+
1
<
itemCount
)
{
String
nextGroupId
=
callback
.
getGroupId
(
position
+
1
)
;
//组内最后一个view进入了header
if
(
nextGroupId
!=
groupId
&&
viewBottom
<
textY
)
{
textY
=
viewBottom
;
}
}
//textY - topGap决定了悬浮栏绘制的高度和位置
c
.
drawRect
(
left
,
textY
-
topGap
,
right
,
textY
,
paint
)
;
//left+2*alignBottom 决定了文本往左偏移的多少(加-->向左移)
//textY-alignBottom 决定了文本往右偏移的多少 (减-->向上移)
c
.
drawText
(
textLine
,
left
+
2
*
alignBottom
,
textY
-
alignBottom
,
textPaint
)
;
}
}
/**
* 判断是不是组中的第一个位置
*
* @param pos
* @return
*/
private
boolean
isFirstInGroup
(
int
pos
)
{
if
(
pos
==
0
)
{
return
true
;
}
else
{
// 因为是根据 字符串内容的相同与否 来判断是不是同意组的,所以此处的标记id 要是String类型
// 如果你只是做联系人列表,悬浮框里显示的只是一个字母,则标记id直接用 int 类型就行了
String
prevGroupId
=
callback
.
getGroupId
(
pos
-
1
)
;
String
groupId
=
callback
.
getGroupId
(
pos
)
;
//判断前一个字符串 与 当前字符串 是否相同
if
(
prevGroupId
.
equals
(
groupId
)
)
{
return
false
;
}
else
{
return
true
;
}
}
}
//定义一个借口方便外界的调用
interface
DecorationCallback
{
String
getGroupId
(
int
position
)
;
String
getGroupFirstLine
(
int
position
)
;
}
}
|
第三步:在向list集合中先把每一个item的 起“标记”作用的字符串都加进去
1
|
setPullAction
(
comingslist
)
;
|
1
2
3
4
5
6
7
8
9
10
|
private
void
setPullAction
(
List
<
WaitMVBean
.
DataBean
.
ComingBean
>
comingslist
)
{
dataList
=
new
ArrayList
<>
(
)
;
for
(
int
i
=
0
;
i
<
comingslist
.
size
(
)
;
i
++
)
{
NameBean
nameBean
=
new
NameBean
(
)
;
String
name0
=
comingslist
.
get
(
i
)
.
getComingTitle
(
)
;
nameBean
.
setName
(
name0
)
;
dataList
.
add
(
nameBean
)
;
}
}
|
第四步:在setAdapter() 前,为RecyclerView添加ItemDecoration:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
recyclerView
.
addItemDecoration
(
new
SectionDecoration
(
dataList
,
mContext
,
new
SectionDecoration
.
DecorationCallback
(
)
{
//返回标记id (即每一项对应的标志性的字符串)
@Override
public
String
getGroupId
(
int
position
)
{
if
(
dataList
.
get
(
position
)
.
getName
(
)
!=
null
)
{
return
dataList
.
get
(
position
)
.
getName
(
)
;
}
return
"-1"
;
}
//获取同组中的第一个内容
@Override
public
String
getGroupFirstLine
(
int
position
)
{
if
(
dataList
.
get
(
position
)
.
getName
(
)
!=
null
)
{
return
dataList
.
get
(
position
)
.
getName
(
)
;
}
return
""
;
}
}
)
)
;
|
这样就完成了~
再看一眼最终效果感受一下:
本文转载自:http://android.jobbole.com/85325/?utm_source=group.jobbole.com&utm_medium=relatedArticles