转载请标明出处:

http://blog.csdn.net/hai_qing_xu_kong/article/details/51013562

本文出自:【顾林海的博客】

前言

上次在京东APP上买东西时,发现首页中间有块叫“京东快报”的栏目,当中广告条能自己主动向上滚动。效果还不错,看到这个效果。第一个念头就是我能不能实现,于是就诞生了这篇文章。

我们看看实现后的效果:

实现原理

起初看到这个效果时,第一个想法就是向上移动动画+定时器,但当我准备写时发现,滚动时上下文字都是逐渐出来的(有点像滑动的),假设用动画的话不行,假设用滑动的话,那就是ListView了。但在看效果图,界面上明明仅仅有一个ITEM,于是。我进行了下面修改:

  • 设置ListView的高度与Item高度一致。这样界面中就仅仅显示一个Item。

  • 自己主动滚动,能够使用ListView的smoothScrollBy(int distance, int duration)方法,第一个參数是滚动的距离,第二个是滚动时间。
  • 自己主动滚动能够通过定时器。使用Handler类自带的postDelyed。

  • ListView的无限向上滚动,能够通过继承BaseAdapter类中重写的getCount()方法时返回Integer.MAX_VALUE使其接近无限大。

  • 触摸事件的拦截,能够通过onInterceptTouchEvent来实现,返回false。

注意:通过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; /**
* <pre>
* 制作主页的向上广告滚动栏
* AdvertisementObject是主页的数据源,假如通过GSON或FastJson获取的实体类
*
* <pre>
* @author 顾林海
*
*/
public class MainScrollUpAdvertisementView extends
BaseAutoScrollUpTextView<AdvertisementObject> { 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是这种:

<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" > <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp" > <ImageView
android:id="@+id/iv_icon"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_centerVertical="true"
android:src="@drawable/icon" /> <com.example.autoscrollup.view.MainScrollUpAdvertisementView
android:id="@+id/main_advertisement_view"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/iv_icon" >
</com.example.autoscrollup.view.MainScrollUpAdvertisementView>
</RelativeLayout> </RelativeLayout>

这里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<AdvertisementObject> mDataList = new ArrayList<AdvertisementObject>(); @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; /**
* <pre>
* 京东快报 自己主动向上滚动的广告基类
* 内部包括TextView的自己主动向上滚动
*
* <pre>
* @author 顾林海
*
* @param <T>
*/
public abstract class BaseAutoScrollUpTextView<T> extends ListView implements
AutoScrollData<T> { /**
* 数据源
*/
private ArrayList<T> mDataList = new ArrayList<T>(); /**
* 字体大小
*/
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<T> _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方法返回的值一致

假设大家喜欢本人的文章,请多多支持,项目地址在最下方

下面是完整的github项目地址,欢迎star,fork

github项目源代码地址:点击【项目源代码】

高仿京东APP首页“京东快报”自己主动向上滚动的广告条的更多相关文章

  1. UpMarqueeTextView-模仿淘宝client向上滚动的广告条

    UpMarqueeTextView一个简单的向上滚动的相似跑马灯效果,项目中用到的时候是接受到推送过来的消息向上滚动一次.没有做动态的gif效果,所以都是一些纯文字的简单记录. UpMarqueeTe ...

  2. 基于Vue全家桶制作的的高仿美团APP

    鸣谢:该项目核心部分参考了慕课网精英讲师ustbhuangyi的课程,其余部分高仿美团APP构建. 前端菜鸟项目,大佬们轻喷~ 美团外卖APP

  3. 仿建设银行APP首页效果

    仿建设银行APP首页效果 下载地址: http://pan.baidu.com/s/1eRMYEzC 下载后需要解压,解压密码联系:390980233  收费88元 HTML+JS实现,下载即可试用. ...

  4. 如何获取app的素材,做出一个高仿的app

    第一步:在iTunes中搜索你想要的app,然后点击下载: 下载完成之后右键点击:在Finder中显示 在finder中右键用"归档工具打开" 会显示如下内容: "显示包 ...

  5. android之官方导航栏ActionBar(三)之高仿优酷首页

    一.问题概述 通过上两篇文章,我们对如何使用ActionBar大致都已经有了认识.在实际应用中,我们更多的是定制ActionBar,那么就需要我们重写或者定义一些样式来修饰ActionBar,来满足具 ...

  6. 自定义View之实现流行的底部菜单栏中间突起:高仿“咸鱼APP”的底部菜单 - z

    http://blog.csdn.net/xh870189248/article/details/75808341 http://blog.csdn.net/yangg194/article/deta ...

  7. 高仿微信app (含有发红包,聊天,消息等)用到 Rxjava+Retrofit+MVP+Glide技术

    https://github.com/GitLqr/LQRWeChat 技术很牛,可以看看

  8. iOS天气动画、高仿QQ菜单、放京东APP、高仿微信、推送消息等源码

    iOS精选源码 TYCyclePagerView iOS上的一个无限循环轮播图组件 iOS高仿微信完整项目源码 想要更简单的推送消息,看本文就对了 ScrollView嵌套ScrolloView解决方 ...

  9. 高仿京东到家APP引导页炫酷动画效果

    前言 京东到家APP的引导页做的可圈可点,插画+动效,简明生动地说明了APP最吸引用户的几个亮点(商品多,价格低,配送快...).本文主要分析拆解这些动画效果,并完成一个高仿Demo,完整的Demo代 ...

随机推荐

  1. html用过标签记录

    nowrap="nowrap" //用于列表中td不许换行 maxlength="100" //用于输入框的长度限制 colspan="2" ...

  2. 联想 K5 Note(L38012)免解锁BL 免rec 保留数据 ROOT Magisk Xposed 救砖 ZUI3.9.218

    >>>重点介绍<<< 第一:本刷机包可卡刷可线刷,刷机包比较大的原因是采用同时兼容卡刷和线刷的格式,所以比较大第二:[卡刷方法]卡刷不要解压刷机包,直接传入手机后用 ...

  3. 编写高质量的js之恰当选用if和switch

    switch结构中存在很多限制,存在这些限制的主要目的是提高多重分支结构的执行效率.因此,如果能够使用switch结构,就不要选择if结构. 无论是使用if结构,还是使用switch结构,应该确保下面 ...

  4. JS——正则

    正则的声明: 1.构造函数:var 变量名= new RegExp(/表达式/); 2.直接量:var 变量名= /表达式/; test()方法: 1.正则对象方法,检测测试字符串是否符合该规则,返回 ...

  5. JS——scroll

    scrollWidth:父div宽度小于子div宽度,父div scrollWidth宽度为子div的宽度,大于则为本身的宽度width+padding scrollHeight:父div高度小于子d ...

  6. Android ExpandableListView的使用详解

    ExpandableListView(可扩展的ListView) ExpandableListVivew是ListView的子类,它在普通ListView的基础上进行了扩展,它把应用中的列表项分为几组 ...

  7. JSP学习笔记 - 内置对象 Request

    1.主要掌握以下5个内置对象及其所属类,必须学会在java docs里根据类名查找相应的方法 request     javax.servlet.http.HttpServletRequest res ...

  8. SPPNet论文翻译-空间金字塔池化Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition

    http://www.dengfanxin.cn/?p=403 原文地址 我对物体检测的一篇重要著作SPPNet的论文的主要部分进行了翻译工作.SPPNet的初衷非常明晰,就是希望网络对输入的尺寸更加 ...

  9. MFC CAD控制权问题

    begineditorcommand(); 隐藏对话框  把控制权交给CAD completeeditorcommand(); 完成交互返回到应用程序 canceleditorcommand CAD被 ...

  10. C - CJSON

    cJSON   API 说明 cJSON_Version() 获得cJSON的版本 cJSON_InitHooks(); 初始化cJSON_Hooks结构体 cJSON_Parse(); 将字符串解析 ...