Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> android高仿京東垂直循環滾動新聞欄

android高仿京東垂直循環滾動新聞欄

編輯:關於android開發

android高仿京東垂直循環滾動新聞欄


京東的垂直滾動新聞欄的實現原理:

就是一個自定義的LinearLayout,並且textView能夠循環垂直滾動,而且條目可以點擊,顯示區域最多顯示2個條目,並且還有交替的屬性垂直移動的動畫效果,通過線程來控制滾動的實現。

不多說看效果:
jd

代碼實現

我們先來為控件設置自定義屬性:



    
        
        
    

自定義控件的獲取屬性方法都一樣:

   //獲取自定義屬性
        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();

然後呢,我們來看一下條目的布局:



    
    

布局很簡單,效果呢:
這裡寫圖片描述
不解釋,我們來寫適配器了:

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 mDatas;
    public JDViewAdapter(List 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();

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved