android高仿京东快报(垂直循环滚动新闻栏)

京东的垂直滚动新闻栏的实现原理:

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

不多说看效果:
android高仿京东快报(垂直循环滚动新闻栏)_第1张图片

代码实现

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


<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();

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


<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高仿京东快报(垂直循环滚动新闻栏)_第2张图片
不解释,我们来写适配器了:

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();

就写到这里吧,很晚了睡觉,欢迎大家前来拍砖。
自定义JDViewdemo传送门
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

新加ViewFlipper实现京东快报

看了大家的评论,然后觉得又学到了新的知识,这里就用ViewFlipper来实现这个功能,哈哈,果断很简单。

来看下简单的代码:

    <ViewFlipper
        android:id="@+id/flipper"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:autoStart="true"
        android:flipInterval="900"
        android:inAnimation="@anim/push_up_in"
        android:outAnimation="@anim/push_up_out" >
        <include layout="@layout/news_one" />
        <include layout="@layout/news_two" />
        <include layout="@layout/news_three" />
        <include layout="@layout/news_four"/>
    ViewFlipper>

是不是很简单利用autoStart 就不需要开线程了,flipInterval设置滚动的时间,inAnimation和outAnimation使用切入切出动画。
传送门:JDViewFlipper.rar

新加TextSwitcher实现京东快报

这也是第一使用TextSwitcher,再次感谢大家的帮助让我学到了新的东西。

TextSwitcher集成了ViewSwitcher, 因此它具有与ViewSwitcher相同的特性:可以在切换View组件时使用动画效果。与ImageSwitcher相似的是,使用TextSwitcher也需要设置一个ViewFactory。与ImageSwitcher不同的是,TextSwitcher所需要的ViewFactory的makeView()方法必须返回一个TextView组件。

TextSwitcher与TextView的功能有点类似,它们都可用于显示文本内容,区别在于TextSwitcher的效果更炫,它可以指定文本切换时的动画效果。现在控件的效果还是不错的,inAnimation和outAnimation可以直接设置滚动动画。


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_centerInParent="true"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:background="@drawable/bg"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingLeft="5dp"
            android:text="京东"
            android:textSize="16sp"
            android:textStyle="bold" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#ff0000"
            android:padding="5dp"
            android:paddingLeft="5dp"
            android:text="快报"
            android:textColor="#ffffff"
            android:textSize="16sp"
            android:textStyle="bold" />

        <View
            android:layout_width="1dp"
            android:layout_height="50dp"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:background="#e0e0e0" />
        
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center_vertical"
            android:layout_gravity="center_vertical"
            android:orientation="horizontal">
               <TextSwitcher
                android:id="@+id/textSwitcher_tag"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:layout_weight="3"
                android:padding="0dp"
                android:gravity="center_vertical"
                android:layout_gravity="center_vertical"
                android:inAnimation="@anim/push_up_in"
                android:outAnimation="@anim/push_up_out">  
                TextSwitcher>
                <TextSwitcher
                android:id="@+id/textSwitcher_title"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:layout_weight="1"
                android:padding="0dp"
                android:gravity="center_vertical"
                android:layout_gravity="center_vertical"
                android:inAnimation="@anim/push_up_in"
                android:outAnimation="@anim/push_up_out">    
                TextSwitcher>
        LinearLayout>
    LinearLayout>
RelativeLayout>

布局也就是这么简单,然后呢为TextSwitcher设置ViewFactory,该TextSwitcher即可正常工作。唯一不足的是

textSwitcher.setFactory(new ViewFactory() {

      @Override
      public View makeView() {
        TextView tv = new TextView(context);
         ......
        return tv;
      }
    });

只能返回textView不能加载自己想要的控件。然后需要使用线程来滚动textSwitcher实现你想要的功能。
下面看具体代码:

package com.losileeya.jdtextswitcher;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.TypedValue;
import android.view.View;
import android.widget.TextSwitcher;
import android.widget.TextView;
import android.widget.ViewSwitcher;
public class MainActivity extends AppCompatActivity {
    private TextSwitcher textSwitcher_tag,textSwitcher_title;
    // 要显示的文本
    String[] tags = new String[]
            {
                    "最新",
                    "最火爆",
                    "HOT",
                    "new"
            };
    // 要显示的文本
    String[] titles = new String[]
            {
                    "瑞士维氏军刀 新品满200-50",
                    "家居家装焕新季,讲199减100!",
                    "带上相机去春游,尼康低至477",
                    "价格惊呆!电信千兆光纤上市"
            };
    private int curStr;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textSwitcher_tag= (TextSwitcher) findViewById(R.id.textSwitcher_tag);
        textSwitcher_title= (TextSwitcher) findViewById(R.id.textSwitcher_title);
        textSwitcher_title.setFactory(new ViewSwitcher.ViewFactory() {
            @Override
            public View makeView() {
                final TextView tv = new   
                TextView(MainActivity.this);
                tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
                tv.setPadding(20, 20, 20, 20);
                return tv;
            }
        });
        textSwitcher_tag.setFactory(new ViewSwitcher.ViewFactory() {
            @Override
            public View makeView() {
                final TextView tv = new  
                TextView(MainActivity.this);
                tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
                tv.setPadding(30, 20, 20,20);
                tv.setTextColor(Color.RED);
               tv.setBackgroundResource(R.drawable.corner);
                return tv;
            }
        });
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                textSwitcher_tag.setText(tags[curStr++ %    
                tags.length]);
                textSwitcher_title.setText(titles[curStr++   
                % titles.length]);
                handler.postDelayed(this, 1000);
            }
        }, 1000);
    }
}

所有的代码就搞完了,哈哈,这里再次谢谢大家。
传送门:JDTextSwitcher.rar

你可能感兴趣的:(android,安卓特效开发)