Android高仿京东垂直循环滚动新闻栏

时间:2021-08-14 08:32:45

实现思路其实很简单,就是一个自定义的linearlayout,并且textview能够循环垂直滚动,而且条目可以点击,显示区域最多显示2个条目,并且还有交替的属性垂直移动的动画效果,通过线程来控制滚动的实现。

不多说看效果:

Android高仿京东垂直循环滚动新闻栏

代码实现

我们先来为控件设置自定义属性:

?
1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="jdadverview">
<attr name="gap" format="integer" />
<attr name="animduration" format="integer"/>
</declare-styleable>
</resources>
自定义控件的获取属性方法都一样:
?
1
2
3
4
5
6
7
//获取自定义属性
typedarray array = context.obtainstyledattributes(attrs, r.styleable.jdadverview);
madverheight = typedvalue.applydimension(typedvalue.complex_unit_dip, jdadverheight, getresources().getdisplaymetrics());
int gap = array.getinteger(r.styleable.jdadverview_gap, mgap);
int animduration = array.getinteger(r.styleable.jdadverview_animduration, manimduration);
//关闭清空typedarray,防止内存泄露
array.recycle();

然后呢,我们来看一下条目的布局:

?
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
<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#ffffff"
android:gravity="center_vertical"
android:orientation="horizontal">
<textview
android:id="@+id/tag"
android:textcolor="#ff0000"
android:layout_marginleft="10dp"
android:text="最新"
android:background="@drawable/corner"
android:textsize="18sp"
android:padding="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<textview
android:id="@+id/title"
android:layout_marginleft="10dp"
android:singleline="true"
android:ellipsize="end"
android:textsize="20sp"
android:text="价格惊呆!电信千兆光纤上市"
android:textcolor="#000000"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</linearlayout>

布局很简单,效果呢:

Android高仿京东垂直循环滚动新闻栏

不解释,我们来写适配器了:

?
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
package com.example.jdadvernotice;
import android.view.layoutinflater;
import android.view.view;
import android.widget.textview;
import android.widget.toast;
import com.example.jdadvernotice.entity.advernotice;
import com.example.jdadvernotice.view.jdadverview;
import java.util.list;
/**
* created by administrator on 2016/3/20.
* 京东广告栏数据适配器
*
*/
public class jdviewadapter {
private list<advernotice> mdatas;
public jdviewadapter(list<advernotice> mdatas) {
this.mdatas = mdatas;
if (mdatas == null || mdatas.isempty()) {
throw new runtimeexception("nothing to show");
}
}
/**
* 获取数据的条数
* @return
*/
public int getcount() {
return mdatas == null ? 0 : mdatas.size();
}
 
/**
* 获取摸个数据
* @param position
* @return
*/
public advernotice getitem(int position) {
return mdatas.get(position);
}
/**
* 获取条目布局
* @param parent
* @return
*/
public view getview(jdadverview parent) {
return layoutinflater.from(parent.getcontext()).inflate(r.layout.item, null);
}
 
/**
* 条目数据适配
* @param view
* @param data
*/
public void setitem(final view view, final advernotice data) {
textview tv = (textview) view.findviewbyid(r.id.title);
tv.settext(data.title);
textview tag = (textview) view.findviewbyid(r.id.tag);
tag.settext(data.url);
//你可以增加点击事件
view.setonclicklistener(new view.onclicklistener() {
@override
public void onclick(view v) {
//比如打开url
toast.maketext(view.getcontext(), data.url, toast.length_short).show();
}
});
}
}

然后我们就来自定义view:

?
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
package com.example.jdadvernotice.view;
import android.animation.animator;
import android.animation.animatorlisteneradapter;
import android.animation.animatorset;
import android.animation.objectanimator;
import android.content.context;
import android.content.res.configuration;
import android.content.res.typedarray;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.util.attributeset;
import android.util.typedvalue;
import android.view.view;
import android.widget.linearlayout;
import com.example.jdadvernotice.jdviewadapter;
import com.example.jdadvernotice.r;
/**
* created by zengyu on 2016/3/20.
*/
public class jdadverview extends linearlayout {
//控件高度
private float madverheight = 0f;
//间隔时间
private final int mgap = 4000;
//动画间隔时间
private final int manimduration = 1000;
//显示文字的尺寸
private final float textsize = 20f;
private jdviewadapter madapter;
private final float jdadverheight = 50;
//显示的view
private view mfirstview;
private view msecondview;
//播放的下标
private int mposition;
//线程的标识
private boolean isstarted;
//画笔
private paint mpaint;
 
public jdadverview(context context) {
this(context, null);
}
 
public jdadverview(context context, attributeset attrs) {
this(context, attrs, 0);
}
 
public jdadverview(context context, attributeset attrs, int defstyleattr) {
super(context, attrs, defstyleattr);
init(context, attrs, defstyleattr);
}
 
/**
* 初始化属性
* @param context
* @param attrs
* @param defstyleattr
*/
private void init(context context, attributeset attrs, int defstyleattr) {
//设置为垂直方向
setorientation(vertical);
//抗锯齿效果
mpaint = new paint(paint.anti_alias_flag);
//获取自定义属性
typedarray array = context.obtainstyledattributes(attrs, r.styleable.jdadverview);
madverheight = typedvalue.applydimension(typedvalue.complex_unit_dip, jdadverheight, getresources().getdisplaymetrics());
int gap = array.getinteger(r.styleable.jdadverview_gap, mgap);
int animduration = array.getinteger(r.styleable.jdadverview_animduration, manimduration);
 
if (mgap <= manimduration) {
gap = mgap;
animduration = manimduration;
}
//关闭清空typedarray
array.recycle();
}
 
/**
* 设置数据
*/
public void setadapter(jdviewadapter adapter) {
this.madapter = adapter;
setupadapter();
}
 
/**
* 开启线程
*/
public void start() {
 
if (!isstarted && madapter.getcount() > 1) {
isstarted = true;
postdelayed(mrunnable, mgap);//间隔mgap刷新一次ui
}
}
 
/**
* 暂停滚动
*/
public void stop() {
//移除handle更新
removecallbacks(mrunnable);
//暂停线程
isstarted = false;
}
/**
* 设置数据适配
*/
private void setupadapter() {
//移除所有view
removeallviews();
//只有一条数据,不滚东
if (madapter.getcount() == 1) {
mfirstview = madapter.getview(this);
madapter.setitem(mfirstview, madapter.getitem(0));
addview(mfirstview);
} else {
//多个数据
mfirstview = madapter.getview(this);
msecondview = madapter.getview(this);
madapter.setitem(mfirstview, madapter.getitem(0));
madapter.setitem(msecondview, madapter.getitem(1));
//把2个添加到此控件里
addview(mfirstview);
addview(msecondview);
mposition = 1;
isstarted = false;
}
}
/**
* 测量控件的宽高
*
* @param widthmeasurespec
* @param heightmeasurespec
*/
@override
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
super.onmeasure(widthmeasurespec, heightmeasurespec);
if (layoutparams.wrap_content == getlayoutparams().height) {
getlayoutparams().height = (int) madverheight;
} else {
madverheight = getheight();
}
 
if (mfirstview != null) {
mfirstview.getlayoutparams().height = (int) madverheight;
}
if (msecondview != null) {
msecondview.getlayoutparams().height = (int) madverheight;
}
}
 
/**
* 画布局
*
* @param canvas
*/
@override
protected void ondraw(canvas canvas) {
super.ondraw(canvas);
mpaint.setcolor(color.white);
mpaint.settextsize(typedvalue.applydimension(typedvalue.complex_unit_sp, textsize, getresources().getdisplaymetrics()));
mpaint.setstyle(paint.style.stroke);
canvas.drawtext("瑞士维氏军刀", textsize, getheight() * 2 / 3, mpaint);//写文字2/3的高度
}
/**
* 垂直滚蛋
*/
private void performswitch() {
//属性动画控制控件滚动,y轴方向移动
objectanimator animator1 = objectanimator.offloat(mfirstview, "translationy", mfirstview.gettranslationy() - madverheight);
objectanimator animator2 = objectanimator.offloat(msecondview, "translationy", msecondview.gettranslationy() - madverheight);
//动画集
animatorset set = new animatorset();
set.playtogether(animator1, animator2);//2个动画一起
set.addlistener(new animatorlisteneradapter() {
@override
public void onanimationend(animator animation) {//动画结束
mfirstview.settranslationy(0);
msecondview.settranslationy(0);
view removedview = getchildat(0);//获得第一个子布局
mposition++;
//设置显示的布局
madapter.setitem(removedview, madapter.getitem(mposition % madapter.getcount()));
//移除前一个view
removeview(removedview);
//添加下一个view
addview(removedview, 1);
}
});
set.setduration(manimduration);//持续时间
set.start();//开启动画
}
private animrunnable mrunnable = new animrunnable();
private class animrunnable implements runnable {
@override
public void run() {
performswitch();
postdelayed(this, mgap);
}
}
 
/**
* 销毁view的时候调用
*/
@override
protected void ondetachedfromwindow() {
super.ondetachedfromwindow();
//停止滚动
stop();
}
/**
* 屏幕 旋转
*
* @param newconfig
*/
@override
protected void onconfigurationchanged(configuration newconfig) {
super.onconfigurationchanged(newconfig);
}
}

从上面可以看出,控件最多可以显示2个条目,并且用线程控制,根据条目的下标轮流滚动显示。

具体使用代码:

初始化数据:

?
1
2
3
4
5
6
private void initdata() {
datas.add(new advernotice("瑞士维氏军刀 新品满200-50","最新"));
datas.add(new advernotice("家居家装焕新季,讲199减100!","最火爆"));
datas.add(new advernotice("带上相机去春游,尼康低至477","hot"));
datas.add(new advernotice("价格惊呆!电信千兆光纤上市","new"));
}

绑定适配器开启滚动线程:

?
1
2
3
4
5
6
initdata();
final jdviewadapter adapter = new jdviewadapter(datas);
final jdadverview tbview = (jdadverview) findviewbyid(r.id.jdadver);
tbview.setadapter(adapter);
//开启线程滚东
tbview.start();

就写到这里吧,很晚了睡觉,欢迎大家前来拍砖。

以上内容是针对android高仿京东垂直循环滚动新闻栏的全部介绍,希望对大家以上帮助!