转载请标明出处:
http://blog.csdn.net/hai_qing_xu_kong/article/details/51013562
本文出自:【顾林海的博客】
##前言
上次在京东APP上买东西时,发现首页中间有块叫“京东快报”的栏目,其中广告条能自动向上滚动,效果还不错,看到这个效果,第一个念头就是我能不能实现,于是就诞生了这篇文章。
我们看看实现后的效果:
##实现原理
起初看到这个效果时,第一个想法就是向上移动动画+定时器,但当我准备写时发现,滚动时上下文字都是逐渐出来的(有点像滑动的),如果用动画的话不行,如果用滑动的话,那就是ListView了,但在看效果图,界面上明明只有一个ITEM,于是,我进行了以下改动:
注意:通过smoothScrollBy方法滚动时,由于布局中的高度时dp,但这里面的第一个参数是sp,因此需要将dp转sp,转换完毕后的是float,但方法中是需要int,这样的话有可能导致小数位的丢失,自动滚动产生偏差,可以通过setSelection(int position)方法纠正位置,在smoothScrollBy方法调用后执行setSelection方法。
##控件的使用
根据业务场景不同,如果是主页的广告条,可以创建MainScrollUpAdvertisementView类继承自BaseAutoScrollUpTextView,BaseAutoScrollUpTextView后尖括号中是广告的数据类型,这里假设是AdvertisementObject。
1、创建我们的广告类
package com.example.autoscrollup.entity;
import java.io.Serializable;
/**
* 获取的首页广告条数据
*
* @author 顾林海
*
*/
public class AdvertisementObject implements Serializable {
public String title;
public String info;
}
2、创建MainScrollUpAdvertisementView类继承自BaseAutoScrollUpTextView:
package com.example.autoscrollup.view;
import android.content.Context;
import android.util.AttributeSet;
import com.example.autoscrollup.entity.AdvertisementObject;
import com.example.autoscrollup.view.base.BaseAutoScrollUpTextView;
/**
*
* 制作主页的向上广告滚动条
* AdvertisementObject是主页的数据源,假如通过GSON或FastJson获取的实体类
*
*
* @author 顾林海
*
*/
public class MainScrollUpAdvertisementView extends
BaseAutoScrollUpTextView {
public MainScrollUpAdvertisementView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public MainScrollUpAdvertisementView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MainScrollUpAdvertisementView(Context context) {
super(context);
}
@Override
public String getTextTitle(AdvertisementObject data) {
return data.title;
}
@Override
public String getTextInfo(AdvertisementObject data) {
return data.info;
}
/**
* 这里面的高度应该和你的xml里设置的高度一致
*/
@Override
protected int getAdertisementHeight() {
return 40;
}
}
通过getTextTitle、getTextInfo、getAdertisementHeight方法获取标题、内容、以及整个广告条的高度。
这里面的getAdertisementHeight方法返回的高度必须与你将要创建的xml文件中MainScrollUpAdvertisementView 控件高度一致,比如上面是40,那我们创建的xml是这样的:
这里android:layout_height="40dp"设置为40,与我们定义的MainScrollUpAdvertisementView 类中的getAdertisementHeight方法返回的高度一致。
3、在我们的Activity中使用定义的MainScrollUpAdvertisementView 控件:
package com.example.autoscrollup;
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;
import com.example.autoscrollup.entity.AdvertisementObject;
import com.example.autoscrollup.view.MainScrollUpAdvertisementView;
import com.example.autoscrollup.view.base.BaseAutoScrollUpTextView.OnItemClickListener;
public class MainActivity extends Activity {
private MainScrollUpAdvertisementView mMainScrollUpAdvertisementView;
private ArrayList mDataList = new ArrayList();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initViews();
}
/**
* 模拟网络获取数据
*/
private void initData() {
AdvertisementObject advertisementObject = new AdvertisementObject();
advertisementObject.title = "爆";
advertisementObject.info = "踏青零食上京东,百万零食1元秒";
mDataList.add(advertisementObject);
advertisementObject = new AdvertisementObject();
advertisementObject.title = "公告";
advertisementObject.info = "看老刘中国行,满129减50!";
mDataList.add(advertisementObject);
advertisementObject = new AdvertisementObject();
advertisementObject.title = "爆";
advertisementObject.info = "高姿CC霜全渠道新品首发,领券199减50,点击查看";
mDataList.add(advertisementObject);
}
private void initViews() {
mMainScrollUpAdvertisementView = (MainScrollUpAdvertisementView) findViewById(R.id.main_advertisement_view);
mMainScrollUpAdvertisementView.setData(mDataList);
mMainScrollUpAdvertisementView.setTextSize(15);
mMainScrollUpAdvertisementView
.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(int position) {
Toast.makeText(MainActivity.this,
"点击了第" + position + "个广告条", Toast.LENGTH_SHORT)
.show();
}
});
mMainScrollUpAdvertisementView.setTimer(2000);
mMainScrollUpAdvertisementView.start();
}
}
注册我们的控件,为控件添加数据通过setData方法添加网络获取到的数据。通过setTextSize设置广告条中文字的大小,通过setOnItemClickListener方法设置监听事件,通过setTimer方法设置滚动的间隔时间,最后通过start方法开启滚动。其中stop方法用于在Activity暂停或销毁时调用,上面暂未写出,请大家自行添加。
至此使用完毕,整体使用还是挺简单的。
##代码讲解
以下是对BaseAutoScrollUpTextView这个基类的说明,先贴出完整的源代码:
package com.example.autoscrollup.view.base;
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Color;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.example.autoscrollup.R;
/**
*
* 京东快报 自动向上滚动的广告基类
* 内部包含TextView的自动向上滚动
*
*
* @author 顾林海
*
* @param
*/
public abstract class BaseAutoScrollUpTextView extends ListView implements
AutoScrollData {
/**
* 数据源
*/
private ArrayList mDataList = new ArrayList();
/**
* 字体大小
*/
private float mSize=16;
/**
* 数据总数
*/
private int mMax;
private int position = -1;
/**
* 向上滚动距离
*/
private int scroll_Y;
private int mScrollY;
/**
* 适配器
*/
private AutoScrollAdapter mAutoScrollAdapter = new AutoScrollAdapter();
/**
* 监听器
*/
private OnItemClickListener mOnItemClickListener;
private long mTimer = 1000;
private Context mContext;
/**
* 获取高度
*
* @return
*/
protected abstract int getAdertisementHeight();
private Handler handler = new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
// 开启轮播
switchItem();
handler.postDelayed(this, mTimer);
}
};
public interface OnItemClickListener {
public void onItemClick(int position);
}
public BaseAutoScrollUpTextView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
this.mContext = context;
mScrollY = dip2px(getAdertisementHeight());
init();
}
public BaseAutoScrollUpTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BaseAutoScrollUpTextView(Context context) {
this(context, null);
}
private void init() {
this.setDivider(null);
this.setFastScrollEnabled(false);
this.setDividerHeight(0);
this.setEnabled(false);
}
/**
* dp-->px
*
* @param dipValue
* @return
*/
private int dip2px(float dipValue) {
final float scale = mContext.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
/**
* 开始轮播
*/
private void switchItem() {
if (position == -1) {
scroll_Y = 0;
} else {
scroll_Y = mScrollY;
}
smoothScrollBy(scroll_Y, 2000);
setSelection(position);
position++;
}
/**
* 广告条适配器
*
* @author 顾林海
*
*/
private class AutoScrollAdapter extends BaseAdapter {
@Override
public int getCount() {
final int count = mDataList == null ? 0 : mDataList.size();
return count > 1 ? Integer.MAX_VALUE : count;
}
@Override
public Object getItem(int position) {
return mDataList.get(position % mMax);
}
@Override
public long getItemId(int position) {
return position % mMax;
}
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
ViewHolder viewHolder;
if (null == convertView) {
viewHolder = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(
R.layout.item_layout, null);
viewHolder.mTitleView = (TextView) convertView
.findViewById(R.id.tv_title);
viewHolder.mInfoView = (TextView) convertView
.findViewById(R.id.tv_info);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
T data = mDataList.get(position % mMax);
viewHolder.mTitleView
.setLayoutParams(new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
dip2px(getAdertisementHeight())));
viewHolder.mTitleView.setTextSize(mSize);
viewHolder.mInfoView.setTextSize(mSize);
viewHolder.mTitleView.setText(getTextTitle(data));
viewHolder.mInfoView.setText(getTextInfo(data));
convertView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mOnItemClickListener.onItemClick(position % mMax);
}
});
return convertView;
}
}
static class ViewHolder {
TextView mTitleView;// 标题
TextView mInfoView;// 内容
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
/**
* 添加数据
*
* @param _datas
*/
public void setData(ArrayList _datas) {
mDataList.clear();
mDataList.addAll(_datas);
mMax = mDataList == null ? 0 : mDataList.size();
this.setAdapter(mAutoScrollAdapter);
mAutoScrollAdapter.notifyDataSetChanged();
}
/**
* 设置文字大小
* @param size
*/
public void setTextSize(float _size){
this.mSize=_size;
}
/**
* 设置监听事件
*/
public void setOnItemClickListener(OnItemClickListener _listener) {
this.mOnItemClickListener = _listener;
}
/**
* 设置轮播间隔时间
*
* @param _time
* 毫秒单位
*/
public void setTimer(long _time) {
this.mTimer = _time;
}
/**
* 开启轮播
*/
public void start() {
handler.postDelayed(runnable, 1000);
}
/**
* 关闭轮播
*/
public void stop() {
handler.removeCallbacks(runnable);
}
}
以上主要是通过Handler类自带的postDelyed实现一个定时的轮播,轮播时调用了ListView的:
smoothScrollBy(scroll_Y, 2000);
setSelection(position);
数据的回调主要是定义了一个范型接口,范型接口的具体实现延迟到子类实现,这样方便大家格局不同场景下定义不同的广告条。
最后的最后大家使用时一定要注意在xml中使用你自己定义的广告条(继承BaseAutoScrollUpTextView),高度一定要与子类getAdertisementHeight方法返回的值一致
如果大家喜欢本人的文章,请多多支持,项目地址在最下方