Android中仿淘宝首页顶部滚动自定义HorizontalScrollView定时水平自动切换图片

  • 自定义ADPager

自定义水平滚动的ScrollView效仿ViewPager

当遇到要在ViewPager中添加多张网络请求图片的情况下,不能进行复用,导致每次都要重新去求情已经请求过的数据致使流量数据过大

自定义的数据结构解决了这个问题,固定传递的图片数据之后进行统一请求,完成后进行页面切换数据复用

代码中涉及网络请求是用的Volley网络请求框架
PicCarousel是网络数据请求的URL相关数据(使用者自己需要的URL)

public class ADPager extends HorizontalScrollView implements View.OnClickListener{

    private final int VELOCITY_SLOT = 1000;
private final int DEFAULT_AUTOPLAY_DURATION = 5000;
private List<PicCarousel> noticeList;
private LinearLayout container;
private LinearLayout.LayoutParams linearLayoutParams;
private ImageLoader mImageLoader;
// private DisplayImageOptions imageOptions;
private VelocityTracker velocityTracker;
private OnADPageClickListener mADPageClickListener;
private int mCurrPage = 0; private long mDuration = DEFAULT_AUTOPLAY_DURATION;
private boolean mIsAutoPlaying = false;
private AutoPlayRunnable mAutoPlayRunnable = new AutoPlayRunnable(); private int mMaximumVelocity; private float mCircleRadius; private Paint mStrokePaint;
private Paint mFillPaint; public ADPager(Context context) {
super(context);
init();
} public ADPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
} public ADPager(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
} private void init() {
Context ctx = getContext();
this.container = new LinearLayout(ctx);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
this.container.setOrientation(LinearLayout.HORIZONTAL);
this.container.setLayoutParams(params);
this.addView(this.container);
this.linearLayoutParams = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT);
this.linearLayoutParams.weight = 1; // 平等分
this.noticeList = new ArrayList<>();
this.setHorizontalScrollBarEnabled(false);
// this.imageLoader = ImageLoader.getInstance(); mImageLoader = new com.android.volley.toolbox.ImageLoader(SingleRequestQueue.getRequestQueue(Utils.getContext()), new BitmapCache()); this.setSmoothScrollingEnabled(true); final Resources res = getResources();
this.mCircleRadius = 8; /** 默认图 **/
NetworkImageView imgView = makeImageView();
this.container.addView(imgView);
/** 默认图结束 **/ /**
* 设置松手时velocity的追踪
*/
final ViewConfiguration configuration = ViewConfiguration.get(ctx);
this.mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); // DisplayImageOptions.Builder builder = new DisplayImageOptions.Builder();
// builder.cacheInMemory(true).cacheOnDisc(true)
// .showImageForEmptyUri(R.mipmap.def_pic)
// .showImageOnLoading(R.mipmap.def_pic)
// .showImageOnFail(R.mipmap.def_pic);
// imageOptions = builder.build(); initPaint();
} private void initPaint() {
mStrokePaint = new Paint();
mStrokePaint.setStrokeWidth(1.0f);
mStrokePaint.setStyle(Paint.Style.STROKE);
mStrokePaint.setColor(Color.WHITE);
mStrokePaint.setAntiAlias(true); mFillPaint = new Paint();
mFillPaint.setColor(Color.WHITE);
mFillPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mFillPaint.setAntiAlias(true);
} private NetworkImageView makeImageView() {
Context ctx = getContext();
NetworkImageView imgView = new NetworkImageView(ctx);
imgView.setLayoutParams(this.linearLayoutParams);
imgView.setDefaultImageResId(R.mipmap.def_pic);
imgView.setScaleType(NetworkImageView.ScaleType.CENTER_CROP);
return imgView;
} /**
* 设置 image的url
*
* @param noticeList
*/
public void setImageUrl(List<PicCarousel> noticeList) {
this.noticeList = noticeList;
int size = noticeList.size();
this.container.removeAllViews();
NetworkImageView imgView;
int position;
if (size == 0) {
imgView = makeImageView();
imgView.setImageResource(R.mipmap.def_pic);
this.container.addView(imgView);
return;
}
if (size > 1) {
imgView = makeImageView();
position = size - 1;
String lastUrl = noticeList.get(position).getPicUrl();
imgView.setTag(position);
imgView.setOnClickListener(this);
/**
* 使用Volley框架加载图片更加快捷,使缓存在一处用于初始化显示
* */
// imageLoader.displayImage(lastUrl, imgView, imageOptions);
imgView.setImageUrl(lastUrl, mImageLoader);
this.container.addView(imgView);
}
position = 0;
for (PicCarousel notice : noticeList) {
imgView = makeImageView();
imgView.setTag(position);
imgView.setOnClickListener(this);
// imageLoader.displayImage(notice.getPicUrl(), imgView, imageOptions);
imgView.setImageUrl(notice.getPicUrl(), mImageLoader);
this.container.addView(imgView);
position ++;
}
if (size > 1) {
String firstUrl = noticeList.get(0).getPicUrl();
imgView = makeImageView();
imgView.setTag(0);
imgView.setOnClickListener(this);
// imageLoader.displayImage(firstUrl, imgView, imageOptions);
imgView.setImageUrl(firstUrl, mImageLoader);
this.container.addView(imgView);
}
this.requestLayout();
this.scrollToPage(0, false);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int size = this.noticeList.size();
int imageLength;
if (size > 1) {
imageLength = size + 2;
} else {
imageLength = 1;
}
int containerSize = widthSize * imageLength;
switch (widthMode) {
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY: {
int childWidthSpec = MeasureSpec.makeMeasureSpec(containerSize, MeasureSpec.EXACTLY);
this.container.measure(childWidthSpec, heightMeasureSpec);
break;
}
case MeasureSpec.UNSPECIFIED: {
throw new RuntimeException("Can not be unspecified");
}
}
} @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN: {
if (mIsAutoPlaying) {
removeCallbacks(mAutoPlayRunnable);
}
break;
}
}
return super.onInterceptTouchEvent(ev);
} @Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getActionMasked();
initVelocityTrackerIfNeed();
velocityTracker.addMovement(ev);
switch (action) {
case MotionEvent.ACTION_DOWN: {
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
float velocityX = velocityTracker.getXVelocity();
int scrollX = this.getScrollX();
int width = this.container.getChildAt(0).getWidth();
int page;
if (Math.abs(velocityX) > VELOCITY_SLOT) {
page = scrollX / width;
if (velocityX > 0) {
page = page - 1;
}
} else {
page = (int)Math.round(scrollX * 1.0 / width) - 1;
}
this.scrollToPage(page, true); recycleVelocityTracker();
if (mIsAutoPlaying) {
postDelayed(mAutoPlayRunnable, mDuration);
}
return true;
}
}
return super.onTouchEvent(ev);
} private void initVelocityTrackerIfNeed() {
if (velocityTracker == null) {
velocityTracker = VelocityTracker.obtain();
}
} private void recycleVelocityTracker() {
if (velocityTracker != null) {
velocityTracker.recycle();
velocityTracker = null;
}
} @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
this.scrollToPage(0, false);
super.onLayout(changed, l, t, r, b);
} /**
* 滚动到某个页面
*
* @param page 页面第n页
* @param smooth 滑动
*/
public void scrollToPage(int page, boolean smooth) {
int size = this.noticeList.size();
if (page < 0) {
page = size - 1;
}
if (size > 1) {
int width = this.container.getChildAt(0).getWidth();
mCurrPage = page;
if (mCurrPage == size) {
mCurrPage = 0;
}
if (!smooth) {
this.scrollTo(width * (page + 1), 0);
} else {
this.smoothScrollTo(width * (page + 1), 0);
}
} else {
mCurrPage = size - 1;
this.scrollTo(0, 0);
}
} @Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
postInvalidate();
} private class AutoPlayRunnable implements Runnable {
@Override
public void run() {
if(mIsAutoPlaying){
int size = noticeList.size();
int targetPage = mCurrPage + 1;
if (targetPage >= size) {
targetPage = 0;
}
scrollToPage(targetPage, true);
postDelayed(mAutoPlayRunnable, mDuration);
} }
} public void setAutoPlay(boolean autoPlay) {
this.setAutoPlay(autoPlay, DEFAULT_AUTOPLAY_DURATION);
} public void setAutoPlay(boolean autoPlay, long duration) {
mIsAutoPlaying = autoPlay;
mDuration = duration;
removeCallbacks(mAutoPlayRunnable);
if (autoPlay) {
postDelayed(mAutoPlayRunnable, duration);
}
} @TargetApi(Build.VERSION_CODES.GINGERBREAD)
@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
int width = this.container.getChildAt(0).getWidth();
int size = this.noticeList.size();
if (clampedX) {
if (scrollX > 0) {
mCurrPage = 0;
scrollTo(width, 0);
} else {
mCurrPage = size - 1;
scrollTo(width * size, 0);
}
}
} public void setOnPageClickListener(OnADPageClickListener l) {
this.mADPageClickListener = l;
} public OnADPageClickListener getOnPageClickListener() {
return this.mADPageClickListener;
} @Override
public void onClick(View v) {
Integer position = (Integer) v.getTag();
if (this.mADPageClickListener != null) {
this.mADPageClickListener.onPageClick(position);
}
} public static interface OnADPageClickListener {
public void onPageClick(int page);
} @Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
drawCircle(canvas);
} private void drawCircle(Canvas canvas) {
int width = this.getWidth();
int height = this.getHeight(); float threeRadius = 3 * mCircleRadius; int size = this.noticeList.size();
int circleLayoutWidth = (int)(threeRadius * size - mCircleRadius); int offsetX = (int)((width - circleLayoutWidth) / 2 + mCircleRadius) + this.getScrollX(); // start pos
int offsetY = (int)(height - 15 - mCircleRadius); // padding Bottom 10px int iLoop;
for (iLoop = 0; iLoop < size; iLoop ++) {
canvas.drawCircle(offsetX, offsetY, mCircleRadius, mStrokePaint); if (iLoop == mCurrPage) {
canvas.drawCircle(offsetX, offsetY, mCircleRadius, mFillPaint);
} offsetX += threeRadius; }
}
}

使用Volley框架首先要在项目中导入Volley.jar包进行依赖,然后就要编写相应的BitmapCache

public class BitmapCache implements ImageLoader.ImageCache {
private String TAG=BitmapCache.class.getSimpleName();
private LruCache<String, Bitmap> mCache; public BitmapCache() {
/** 1.缓存区大小10M 单位是byte */
int maxSize =(int) (Runtime.getRuntime().maxMemory() / 1024);
mCache = new LruCache<String, Bitmap>(maxSize) {
/** 2.重写sizeOf方法 返回条目的大小*/
@Override
protected int sizeOf(String key, Bitmap bitmap) {
/** 返回bitmap这个entry的大小,统一计算单位 */
// Log.e(TAG,"大小+"+bitmap.getRowBytes() * bitmap.getHeight());
return bitmap.getRowBytes() * bitmap.getHeight();
}
};
} /**
* 从缓存中取数据
*
* @param url
* @return
*/
@Override
public Bitmap getBitmap(String url) {
// LogUtil.i("BitmapCache", "从内存中取出 -------->");
return mCache.get(url);
} /**
* 往缓存中写数据
*
* @param url
* @param bitmap
*/
@Override
public void putBitmap(String url, Bitmap bitmap) {
// LogUtil.i("BitmapCache", "存放到内存 <------");
mCache.put(url, bitmap);
}
}

这里为了避免过多的Volley请求发出导致OOM异常这里需要对Volley的请求做一个单例设计模式操作

public class SingleRequestQueue {
private static RequestQueue mQueue; private SingleRequestQueue(Context context) {
mQueue = Volley.newRequestQueue(context);
} public static synchronized RequestQueue getRequestQueue(Context context){
if (mQueue == null){
new SingleRequestQueue(context.getApplicationContext());
}
return mQueue;
}
}

在要实现的功能代码中添加


home_pager.setImageUrl(mPicList);//添加URL进行数据获取
home_pager.setAutoPlay(true, 3000);//自动轮播开始并设置多少秒滚动一次
home_pager.setOnPageClickListener(this);//相应的点击事件

Android中仿淘宝首页顶部滚动自定义HorizontalScrollView定时水平自动切换图片的更多相关文章

  1. Android -- 仿淘宝广告条滚动

    1,在赶项目的时候我们经常会实现下面这个功能,及添加滚动条广告广播,先看一下淘宝的效果 2,这次实现效果主要使用Android自带的ViewFlipper控件,先来看一下我们的它的基本属性和基本方法吧 ...

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

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

  3. 【angularjs】使用angularjs模拟淘宝首页-淘宝头条滚动效果

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  4. Android仿淘宝头条滚动广告条

    之前我使用TextView+Handler+动画,实现了一个简单的仿淘宝广告条的滚动,https://download.csdn.net/download/qq_35605213/9660825: 无 ...

  5. android版高仿淘宝客户端源码V2.3

    android版高仿淘宝客户端源码V2.3,这个版本我已经更新到2.3了,源码也上传到源码天堂那里了,大家可以看一下吧,该应用实现了我们常用的购物功能了,也就是在手机上进行网购的流程的,如查看产品(浏 ...

  6. 模仿淘宝首页写的高仿页面,脚本全用的原生JS,菜鸟一枚高手看了勿喷哈

    自己仿照淘宝首页写的页面,仿真度自己感觉可以.JS脚本全是用原生JavaScript写得,没用框架.高手看了勿喷,请多多指正哈!先上网页截图看看效果,然后上源码: 上源码,先JavaScript : ...

  7. Android仿淘宝继续上拉进入商品详情页的效果,使用双Fragment动画切换;

    仿淘宝继续上拉进入商品详情页的效果,双Fragment实现: 动画效果: slide_above_in.xml <?xml version="1.0" encoding=&q ...

  8. 淘宝首页源码藏美女彩蛋(下)(UED新作2013egg)

    我们已经知道,执行美女会得到"彩蛋",而正是彩蛋做到了taobaoUED展现给大家的神奇的前端魅力.今天我们来看看FP.egg&&FP.egg("%cjo ...

  9. 高仿淘宝和聚美优品商城详情页实现《IT蓝豹》

    高仿淘宝和聚美优品商城详情页实现 android-vertical-slide-view高仿淘宝和聚美优品商城详情页实现,在商品详情页,向上拖动时,可以加载下一页. 使用ViewDragHelper, ...

随机推荐

  1. C register

    1.register修饰符暗示编译程序相应的变量将被频繁地使用,如果可能的话,应将其保存在CPU的寄存器中,以加快其存储速度.例如下面的内存块拷贝代码, /* Procedure for the as ...

  2. 神奇的VIM~转IBM

    % 地址范围符号,代表文件中的所有行,作用等同于地址范围 1,$ . 与任意单字符(换行符除外)匹配,例如 y.s 可以匹配 yas y.s 或 y s 等等. * 与前一字符的0次或多次出现匹配,例 ...

  3. Execel(导出新方法):

    #region 新方法 //var sbHtml = new StringBuilder(); //sbHtml.Append("<table border='1' cellspaci ...

  4. C++ Windows 下 根据进程名获取进程ID 以及该进程下所有窗口的句柄

    #include <windows.h> #include <stdint.h> #include <tlhelp32.h> #include <stdio. ...

  5. android内存分析:heap Snapshot的使用

    网上有很多讲解关于android studio中memory工具的使用,接下来我来说一段在项目中发生的实例:大家可以根据我的这个方法来分析自己项目中的问题 首先我们要通过手动先触发GC操作,点击mem ...

  6. CSS元素居中的常用方法

    只有普通流和绝对定位的元素可以设置居中,浮动元素是不存在居中的. 1.块级元素居中 1) 普通流元素(position : static 或 position : relative) 水平居中:{ m ...

  7. .net DropDownList静态联动

    1.前台 <span id="spnClient" style="margin-left: 30px; margin-top: 10px"> < ...

  8. 使用 apache2 + `mod_proxy_uwsgi` + uwsgi + upstart 部署

    使用 apache2 + mod_proxy_uwsgi + uwsgi + upstart 部署 网上运行 python wsgi 的应用时,大部分的资料都是使用 nginx .uwsgi ,很少资 ...

  9. [SharePoint 2013] Set value for people editor with JSOM

    function PeoplePicker() { this.context = null; this.web = null; this.currentUser = null; this.parent ...

  10. 实现一个小目标,动动小指,分享可得iphone7/ipad/U盘|奥威软件

    为什么很多人喜欢冬天呢?是因为冬天有着“床边挂起长长棉袜,而你做着甜甜美梦”的平安夜?还是因为冬天有着“具有无法言述的浪漫情怀”的圣诞节? 是不是还沉浸在平安夜,圣诞节的双节狂欢中, 好像不管长到多大 ...