Android高仿京东垂直循环滚动新闻栏
程序员文章站
2024-02-28 11:02:04
实现思路其实很简单,就是一个自定义的linearlayout,并且textview能够循环垂直滚动,而且条目可以点击,显示区域最多显示2个条目,并且还有交替的属性垂直移动的...
实现思路其实很简单,就是一个自定义的linearlayout,并且textview能够循环垂直滚动,而且条目可以点击,显示区域最多显示2个条目,并且还有交替的属性垂直移动的动画效果,通过线程来控制滚动的实现。
不多说看效果:
代码实现
我们先来为控件设置自定义属性:
<?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>
自定义控件的获取属性方法都一样:
//获取自定义属性 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();
然后呢,我们来看一下条目的布局:
<?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>
布局很简单,效果呢:
不解释,我们来写适配器了:
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:
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个条目,并且用线程控制,根据条目的下标轮流滚动显示。
具体使用代码:
初始化数据:
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")); }
绑定适配器开启滚动线程:
initdata(); final jdviewadapter adapter = new jdviewadapter(datas); final jdadverview tbview = (jdadverview) findviewbyid(r.id.jdadver); tbview.setadapter(adapter); //开启线程滚东 tbview.start();
就写到这里吧,很晚了睡觉,欢迎大家前来拍砖。
以上内容是针对android高仿京东垂直循环滚动新闻栏的全部介绍,希望对大家以上帮助!
上一篇: JAVA线程用法详解
下一篇: Mybatis 传输List的实现代码