Android高仿京東垂直循環(huán)滾動(dòng)新聞欄
實(shí)現(xiàn)思路其實(shí)很簡(jiǎn)單,就是一個(gè)自定義的LinearLayout,并且textView能夠循環(huán)垂直滾動(dòng),而且條目可以點(diǎn)擊,顯示區(qū)域最多顯示2個(gè)條目,并且還有交替的屬性垂直移動(dòng)的動(dòng)畫效果,通過(guò)線程來(lái)控制滾動(dòng)的實(shí)現(xiàn)。
不多說(shuō)看效果:
代碼實(shí)現(xiàn)
我們先來(lái)為控件設(shè)置自定義屬性:
<?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); //關(guān)閉清空TypedArray,防止內(nèi)存泄露 array.recycle();
然后呢,我們來(lái)看一下條目的布局:
<?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="價(jià)格驚呆!電信千兆光纖上市" android:textColor="#000000" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout>
布局很簡(jiǎn)單,效果呢:
不解釋,我們來(lái)寫適配器了:
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. * 京東廣告欄數(shù)據(jù)適配器 * */ 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"); } } /** * 獲取數(shù)據(jù)的條數(shù) * @return */ public int getCount() { return mDatas == null ? 0 : mDatas.size(); } /** * 獲取摸個(gè)數(shù)據(jù) * @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); } /** * 條目數(shù)據(jù)適配 * @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); //你可以增加點(diǎn)擊事件 view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //比如打開url Toast.makeText(view.getContext(), data.url, Toast.LENGTH_SHORT).show(); } }); } }
然后我們就來(lái)自定義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; //間隔時(shí)間 private final int mGap = 4000; //動(dòng)畫間隔時(shí)間 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; //播放的下標(biāo) private int mPosition; //線程的標(biāo)識(shí) 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) { //設(shè)置為垂直方向 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; } //關(guān)閉清空TypedArray array.recycle(); } /** * 設(shè)置數(shù)據(jù) */ public void setAdapter(JDViewAdapter adapter) { this.mAdapter = adapter; setupAdapter(); } /** * 開啟線程 */ public void start() { if (!isStarted && mAdapter.getCount() > 1) { isStarted = true; postDelayed(mRunnable, mGap);//間隔mgap刷新一次UI } } /** * 暫停滾動(dòng) */ public void stop() { //移除handle更新 removeCallbacks(mRunnable); //暫停線程 isStarted = false; } /** * 設(shè)置數(shù)據(jù)適配 */ private void setupAdapter() { //移除所有view removeAllViews(); //只有一條數(shù)據(jù),不滾東 if (mAdapter.getCount() == 1) { mFirstView = mAdapter.getView(this); mAdapter.setItem(mFirstView, mAdapter.getItem(0)); addView(mFirstView); } else { //多個(gè)數(shù)據(jù) mFirstView = mAdapter.getView(this); mSecondView = mAdapter.getView(this); mAdapter.setItem(mFirstView, mAdapter.getItem(0)); mAdapter.setItem(mSecondView, mAdapter.getItem(1)); //把2個(gè)添加到此控件里 addView(mFirstView); addView(mSecondView); mPosition = 1; isStarted = false; } } /** * 測(cè)量控件的寬高 * * @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() { //屬性動(dòng)畫控制控件滾動(dòng),y軸方向移動(dòng) ObjectAnimator animator1 = ObjectAnimator.ofFloat(mFirstView, "translationY", mFirstView.getTranslationY() - mAdverHeight); ObjectAnimator animator2 = ObjectAnimator.ofFloat(mSecondView, "translationY", mSecondView.getTranslationY() - mAdverHeight); //動(dòng)畫集 AnimatorSet set = new AnimatorSet(); set.playTogether(animator1, animator2);//2個(gè)動(dòng)畫一起 set.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) {//動(dòng)畫結(jié)束 mFirstView.setTranslationY(0); mSecondView.setTranslationY(0); View removedView = getChildAt(0);//獲得第一個(gè)子布局 mPosition++; //設(shè)置顯示的布局 mAdapter.setItem(removedView, mAdapter.getItem(mPosition % mAdapter.getCount())); //移除前一個(gè)view removeView(removedView); //添加下一個(gè)view addView(removedView, 1); } }); set.setDuration(mAnimDuration);//持續(xù)時(shí)間 set.start();//開啟動(dòng)畫 } private AnimRunnable mRunnable = new AnimRunnable(); private class AnimRunnable implements Runnable { @Override public void run() { performSwitch(); postDelayed(this, mGap); } } /** * 銷毀View的時(shí)候調(diào)用 */ @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); //停止?jié)L動(dòng) stop(); } /** * 屏幕 旋轉(zhuǎn) * * @param newConfig */ @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); } }
從上面可以看出,控件最多可以顯示2個(gè)條目,并且用線程控制,根據(jù)條目的下標(biāo)輪流滾動(dòng)顯示。
具體使用代碼:
初始化數(shù)據(jù):
private void initData() { datas.add(new AdverNotice("瑞士維氏軍刀 新品滿200-50","最新")); datas.add(new AdverNotice("家居家裝煥新季,講199減100!","最火爆")); datas.add(new AdverNotice("帶上相機(jī)去春游,尼康低至477","HOT")); datas.add(new AdverNotice("價(jià)格驚呆!電信千兆光纖上市","new")); }
綁定適配器開啟滾動(dòng)線程:
initData(); final JDViewAdapter adapter = new JDViewAdapter(datas); final JDAdverView tbView = (JDAdverView) findViewById(R.id.jdadver); tbView.setAdapter(adapter); //開啟線程滾東 tbView.start();
就寫到這里吧,很晚了睡覺,歡迎大家前來(lái)拍磚。
以上內(nèi)容是針對(duì)Android高仿京東垂直循環(huán)滾動(dòng)新聞欄的全部介紹,希望對(duì)大家以上幫助!
- Android ListView實(shí)現(xiàn)無(wú)限循環(huán)滾動(dòng)
- Android可自定義垂直循環(huán)滾動(dòng)布局
- Android ViewPager無(wú)限循環(huán)滑動(dòng)并可自動(dòng)滾動(dòng)完整實(shí)例
- android水平循環(huán)滾動(dòng)控件使用詳解
- Android使用Recyclerview實(shí)現(xiàn)圖片水平自動(dòng)循環(huán)滾動(dòng)效果
- Android ViewPager實(shí)現(xiàn)智能無(wú)限循環(huán)滾動(dòng)回繞效果
- Android自定義可循環(huán)的滾動(dòng)選擇器CycleWheelView
- Android 使用ViewPager自動(dòng)滾動(dòng)循環(huán)輪播效果
- Android實(shí)現(xiàn)無(wú)限循環(huán)滾動(dòng)
相關(guān)文章
Android中的sqlite查詢數(shù)據(jù)時(shí)去掉重復(fù)值的方法實(shí)例
今天小編就為大家分享一篇關(guān)于Android中的sqlite查詢數(shù)據(jù)時(shí)去掉重復(fù)值的方法實(shí)例,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01Android開發(fā)準(zhǔn)確獲取手機(jī)IP地址的兩種方式
這篇文章主要介紹了Android開發(fā)準(zhǔn)確獲取手機(jī)IP地址的兩種方式,需要的朋友可以參考下2020-03-03Android 自定義View時(shí)使用TypedArray配置樣式屬性詳細(xì)介紹
這篇文章主要介紹了Android 自定義View時(shí)使用TypedArray配置樣式屬性詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下2016-11-11Android Service自啟動(dòng)注意事項(xiàng)分析
這篇文章主要介紹了Android Service自啟動(dòng)注意事項(xiàng),結(jié)合實(shí)例分析了Android Service自啟動(dòng)過(guò)程中屬性設(shè)置的相關(guān)技巧,需要的朋友可以參考下2016-03-03Android實(shí)現(xiàn)在TextView文字過(guò)長(zhǎng)時(shí)省略部分或滾動(dòng)顯示的方法
這篇文章主要介紹了Android實(shí)現(xiàn)在TextView文字過(guò)長(zhǎng)時(shí)省略部分或滾動(dòng)顯示的方法,結(jié)合實(shí)例形式分析了Android中TextView控件文字顯示及滾動(dòng)效果相關(guān)操作技巧,需要的朋友可以參考下2016-10-10Android編程簡(jiǎn)單獲取網(wǎng)絡(luò)上的圖片
這篇文章主要介紹了Android編程簡(jiǎn)單獲取網(wǎng)絡(luò)上的圖片,結(jié)合實(shí)例形式分析了Android獲取網(wǎng)絡(luò)圖片及加載顯示的相關(guān)操作步驟與注意事項(xiàng),需要的朋友可以參考下2016-10-10Android自定義HorizontalScrollView打造超強(qiáng)Gallery效果
這篇文章主要介紹了Android自定義HorizontalScrollView打造圖片橫向滑動(dòng)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05