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

所属分类: 软件编程 / Android 阅读数: 1279
收藏 0 赞 0 分享

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

不多说看效果:

jd

代码实现

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

<?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高仿京东垂直循环滚动新闻栏的全部介绍,希望对大家以上帮助!

更多精彩内容其他人还在看

Android控件系列之CheckBox使用介绍

CheckBox和Button一样,也是一种古老的控件,它的优点在于,不用用户去填写具体的信息,只需轻轻点击,缺点在于只有“是”和“否”两种情况,但我们往往利用它的这个特性,来获取用户的一些信息
收藏 0 赞 0 分享

Android控件系列之EditText使用方法

EditText是接受用户输入信息的最重要控件。通过前面课程的学习,您可能会猜到可以利用EditText.getText()获取它的文本,但真正的项目中,可能没那么简单,需要更多的限制,如文本长度限制,是否数字限制等等
收藏 0 赞 0 分享

Android控件系列之TextView使用介绍

TextView类似一般UI中的Label,TextBlock等控件,只是为了单纯的显示一行或多行文本,本文介绍了Android中文本控件TextView的用法和常用属性的用法
收藏 0 赞 0 分享

asynctask的用法详解

Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行,本文将为您介绍asynctask的用法
收藏 0 赞 0 分享

Android开发 旋转屏幕导致Activity重建解决方法

Android开发文档上专门有一小节解释这个问题。简单来说,Activity是负责与用户交互的最主要机制,接下来为您详细介绍
收藏 0 赞 0 分享

Notification与NotificationManager详细介绍

在Android系统中,发一个状态栏通知还是很方便的。下面我们就来看一下,怎么发送状态栏通知,状态栏通知又有哪些参数可以设置
收藏 0 赞 0 分享

android LinearLayout和RelativeLayout组合实现精确布局方法介绍

用android LinearLayout和RelativeLayout实现精确布局此方法适合很适合新人看
收藏 0 赞 0 分享

android listview优化几种写法详细介绍

这篇文章只是总结下getView里面优化视图的几种写法,需要的朋友可以参考下
收藏 0 赞 0 分享

Android应用开发SharedPreferences存储数据的使用方法

SharedPreferences是Android中最容易理解的数据存储技术,实际上SharedPreferences处理的就是一个key-value(键值对)SharedPreferences常用来存储一些轻量级的数据
收藏 0 赞 0 分享

Android之PreferenceActivity应用详解

为了引入这个概率 首先从需求说起 即:现有某Activity专门用于手机属性设置 那么应该如何做呢
收藏 0 赞 0 分享
查看更多