效果图:

该banner功能有自动切换图片,点击图片可以自定义事件,手动滑动切换,异步加载图片

代码说话:

布局文件:

<!-- 广告位 -->

            <FrameLayout
android:id="@+id/new_recommend"
android:layout_width="fill_parent"
android:layout_height="wrap_content" > <com.cyou.cmall.ui.HorizontalViewPager
android:id="@+id/viewpager"
android:layout_width="fill_parent"
android:layout_height="fill_parent" /> <LinearLayout
android:id="@+id/ll_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="horizontal"
android:paddingBottom="8dp"
android:paddingLeft="26dip" />
</FrameLayout>

布局文件中我自定义了一个HorizontalViewPager,它是在viewpager的基础上做了一些修改,之所以这样做是因为,项目中使用到了下拉刷新控件,该布局最外层还有一个scrollview,会导致scrollview将手势事件拦截,而viewpager得不到滑动手势

下面是HorizontalViewPager的代码,如果不需要处理滑动手势,完全可以使用系统的viewpager控件

/**
* 复写该控件是因为在PullToRefreshScrollView中,viewpager无法水平滑动
*
* @author wangwei_cs
*/
public class HorizontalViewPager extends ViewPager { private GestureDetector mGestureDetector; public HorizontalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
} public HorizontalViewPager(Context context) {
super(context);
init(context);
} private void init(Context context) {
mGestureDetector = new GestureDetector(context, new YScrollDetector());
} @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean dispatchTouchEvent = super.dispatchTouchEvent(ev);
if (dispatchTouchEvent) {
if (mGestureDetector.onTouchEvent(ev)) {
//请求父类放弃事件的处理
requestDisallowInterceptTouchEvent(true);
}
}
return dispatchTouchEvent;
} class YScrollDetector extends SimpleOnGestureListener { @Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
// 如果我们滚动更接近水平方向,返回true,自己处理,否则,让出处理权限
return (Math.abs(distanceX) > Math.abs(distanceY));
}
}
}
</span>

言归正传:在程序oncreate方法中调用一下方法

    /**
* 初始化推荐广告专区
*/
private void initRecommendAd() {
HorizontalViewPager mViewPager = (HorizontalViewPager) findViewById(R.id.viewpager);
mIndicatorLayout = (LinearLayout) findViewById(R.id.ll_indicator);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
android.widget.FrameLayout.LayoutParams.MATCH_PARENT, height * 24 / 100);
mViewPager.setLayoutParams(params);
AdImagePagerAdapter mPagerAdapter = new AdImagePagerAdapter(mCxt, imageUrls, new ViewPagerItemClickListener() { @Override
public void OnViewPagerItemClick(int position) {
if (imageUrls.size() > 0) {
if (imageUrls.size() == 1) {
boolean enable = urlEnable(imageUrls.get(0));
if (enable) {
handleClickEvent(position);
}
} else {
handleClickEvent(position);
}
}
}
});
List<String> lastAdUrls = getLastAdUrls();
if (lastAdUrls == null || lastAdUrls.size() == 0) {
// 没有记录上一次广告url信息,添加一个无效url路径
imageUrls.add(Constants.INVALID_URL);
LogHelper.e(TAG, "no last ad record");
} else {
LogHelper.e(TAG, "show last ad record");
imageUrls.addAll(lastAdUrls);
}
mAdComponent = new RecommendAdComponent(mCxt, mViewPager, mPagerAdapter, imageUrls, 5000,
mIndicatorLayout);
mAdComponent.startUpAdComponent();
mPagerAdapter.notifyDataSetChanged();
}

下面是AdImagePagerAdapter的源码

import java.util.List;

import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.view.PagerAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast; import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.assist.SimpleImageLoadingListener;
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer; /**
* 无限循环adapter
*
* @author wangwei_cs
*/
public class AdImagePagerAdapter extends PagerAdapter { protected static final String TAG = "AdImagePagerAdapter";
private List<String> imageUrls;
private LayoutInflater inflater;
private Context mCxt;
private ViewPagerItemClickListener mListener;
protected ImageLoader imageLoader;
private DisplayImageOptions options; public AdImagePagerAdapter(Context context, List<String> imageUrls, ViewPagerItemClickListener listener) {
this.imageUrls = imageUrls;
this.mCxt = context;
inflater = LayoutInflater.from(context);
this.mListener = listener;
imageLoader = ImageLoader.getInstance(); options = new DisplayImageOptions.Builder()
.showImageForEmptyUri(R.drawable.ad_default)
.showImageOnFail(R.drawable.ad_default)
.showImageOnLoading(R.drawable.ad_default)
.resetViewBeforeLoading(true)
.cacheOnDisc(true)
.imageScaleType(ImageScaleType.EXACTLY)
.bitmapConfig(Bitmap.Config.RGB_565)
.considerExifParams(true)
.displayer(new FadeInBitmapDisplayer(300))
.build();
} @Override
public int getCount() {
if (imageUrls.size() < 2) {
return imageUrls.size();
}
return Integer.MAX_VALUE;
} @Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
} @Override
public Object instantiateItem(ViewGroup container, int position) {
final int index = position % imageUrls.size();
View view = inflater.inflate(R.layout.item_pager_image, container, false);
assert view != null;
ImageView imageView = (ImageView) view.findViewById(R.id.image);
final ProgressBar spinner = (ProgressBar) view.findViewById(R.id.img_loading);
imageLoader.displayImage(imageUrls.get(index), imageView, options,
new SimpleImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
spinner.setVisibility(View.VISIBLE);
} @Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
String message = null;
switch (failReason.getType()) {
case IO_ERROR:
message = "Input/Output error";
break;
case DECODING_ERROR:
message = "Image can't be decoded";
break;
case NETWORK_DENIED:
message = "Downloads are denied";
break;
case OUT_OF_MEMORY:
message = "Out Of Memory error";
break;
case UNKNOWN:
message = "Unknown error";
break;
}
LogHelper.e(TAG, message);
spinner.setVisibility(View.GONE);
} @Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
spinner.setVisibility(View.GONE);
}
}); view.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
if (mListener !=null) {
mListener.OnViewPagerItemClick(index);
}
}
});
container.addView(view);
return view;
} @Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}

下面是重点的RecommendAdComponent自定义的广告推荐组件

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.support.v4.view.ViewPager.PageTransformer;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.LinearLayout;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask; /**
* 展示广告轮转的组件
*
* @author wangwei_cs
*/
public class RecommendAdComponent { /**
* 无效的图片切换时间,如果为0 表示不自动切换
*/
public static final int SWITCH_TIME_INVALID = 0; private Context mCxt; // 图片url集合
private List<String> mImgUrls;
// 图片切换时间
private int mSwitchTime;
//自动滚动的定时器
private Timer mTimer;
// 显示圆点指示器的布局
private LinearLayout mIndicatorLayout;
private ViewPager mViewPager;
private PagerAdapter mPagerAdapter;
private int currentIndex; // 当前页面,在0和getSize()直接
private int pagerCurrent;//在viewpager中,的当前页面,取值在0和Integer.MAX_VALUE之间
private boolean timeRunning; /**
* @param context
* @param viewpager viewPager组件
* @param pagerAdapter
* @param adUrls 装有图片url的集合
* @param switchTime 图片切换时间(ms) {@link RecommendAdComponent#SWITCH_TIME_INVALID}:不自动切换
* @param indicatorLayout 显示圆点指示器的布局
*/
public RecommendAdComponent(Context context, ViewPager viewpager, PagerAdapter pagerAdapter, List<String> adUrls, int switchTime,
LinearLayout indicatorLayout) {
this.mCxt = context;
this.mViewPager = viewpager;
this.mPagerAdapter = pagerAdapter;
this.mImgUrls = adUrls;
this.mSwitchTime = switchTime;
this.mIndicatorLayout = indicatorLayout;
initIndicatorLayout();
mViewPager.setOnPageChangeListener(new MyOnPageChangeListener());
// setViewpagerAnimator();
} /**
* 初始化指示器
*/
private void initIndicatorLayout() {
ImageView iv = null;
if (mIndicatorLayout != null && getSize() < 2) {
// 如果只有一第图时不显示圆点容器
mIndicatorLayout.setVisibility(View.INVISIBLE);
} else if (mIndicatorLayout != null) {
mIndicatorLayout.setVisibility(View.VISIBLE);
for (int i = 0; i < getSize(); i++) {
iv = new ImageView(mCxt);
iv.setTag(i);
int padding = mCxt.getResources().getDimensionPixelSize(R.dimen.indicator_padding);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
params.setMargins(padding, 0, padding, 0);
mIndicatorLayout.addView(iv, params);
}
}
} private void resetIndicatorLayout() {
mIndicatorLayout.removeAllViews();
initIndicatorLayout();
} /**
* 给viewPager设置动画
*/
private void setViewpagerAnimator(){
if (mViewPager !=null) {
PageTransformer pageTransformer=new PageTransformer() { @Override
public void transformPage(View view, float arg1) {
// view.setAnimation(AnimationUtils.loadAnimation(mCxt, android.R.anim.slide_out_right));
view.setAnimation(AnimationUtils.loadAnimation(mCxt, R.anim.right_in));
}
};
mViewPager.setPageTransformer(true, pageTransformer);
}
} /**
* 获取图片集合的size
*
* @return
*/
private int getSize() {
return (mImgUrls == null ? 0 : mImgUrls.size());
} public boolean isEmpty() {
return (mImgUrls == null);
} /**
* 开启组件
*/
public void startUpAdComponent() {
currentIndex = 0;
pagerCurrent = 0;
mViewPager.setAdapter(mPagerAdapter);
mViewPager.setCurrentItem(currentIndex);
updateIndicator(currentIndex);
startTimer();
} /**
* 更新组件中adapter数据
*/
public void updateAdComponent() {
stopTimer();
resetIndicatorLayout();
mPagerAdapter.notifyDataSetChanged();
startUpAdComponent();
} /**
* 在页面销毁的时候调用该方法
*/
public void stopAdComponent() {
stopTimer();
} /**
* 停止自动滚动的任务
*/
public void stopTimer() {
timeRunning = false;
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
} /**
* 开始自动滚动的任务,注意,只有图片个数大于1的时候才会自动滚动
*/
public void startTimer() {
timeRunning = true;
if (mTimer == null && getSize() > 1 && mSwitchTime > 0) {
mTimer = new Timer();
mTimer.schedule(new PagerTimerTask(), mSwitchTime, mSwitchTime);
}
} private class PagerTimerTask extends TimerTask { @Override
public void run() {
currentIndex++;
pagerCurrent++;
mHandler.sendEmptyMessage(0);
}
} private class MyOnPageChangeListener implements OnPageChangeListener { @Override
public void onPageScrollStateChanged(int arg0) {
} @Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
} @Override
public void onPageSelected(int position) {
pagerCurrent = position;
currentIndex = position % getSize();// 更新当前页面
updateIndicator(currentIndex);
}
} /**
* 更新圆点指示器
*/
private void updateIndicator(int position) {
if (!isEmpty() && position < getSize()) {
if (getSize() > 1) {
resetAllIndicator(getSize());// 重置所有的指示器为为选择状态
View v = mIndicatorLayout.findViewWithTag(position);
if (v != null) {
v.setBackgroundResource(R.drawable.circle_indicator_selected);// 点亮
}
}
}
} /**
* 重置所有的指示器
*/
private void resetAllIndicator(int size) {
if (mIndicatorLayout != null) {
for (int i = 0; i < size; i++) {
View v = mIndicatorLayout.findViewWithTag(i);
if (v != null) {
v.setBackgroundResource(R.drawable.circle_indicator_normal);
}
}
}
} @SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
mViewPager.setCurrentItem(pagerCurrent);
};
};
}

当网络加载图片url列表成功之后,只需调用mAdComponent.updateAdComponent();即可

例如我的代码

private void updateAdSources(List<HomeBannerDTO> list) {
imageUrls.clear();
for (HomeBannerDTO dto : list) {
imageUrls.add(dto.getUrl());
}
mBannerList.clear();
mBannerList.addAll(list);
//更新banner组件
mAdComponent.updateAdComponent();
LogHelper.d(TAG, "updateAdComponent .....");
SettingsMgr.setLastRecommendAdList(mCxt, mBannerList);
}

广告banner:手动滑动切换,自动切换,点击跳转,异步加载网络图片的更多相关文章

  1. Ztree异步加载自动展开节点

    在Ztree的官网Demo中,有自动展开的例子,是通过设置节点属性open:true来实现自动展开的,但是在异步加载中,这个属性设置为true也不会自动展开,因为open:true是指在有子节点的情况 ...

  2. ionic UI Component Slides使用:手动滑动后自动滑动失效解决

    在使用ionic的UI组件Slides时,发现手动滑动后,自动滑动失效 然后历经一点点的艰辛查找后找到方法,如下: 页面代码使用 <ion-slides pager loop="tru ...

  3. iScroll.js 向上滑动异步加载数据回弹问题

    iScroll是一款用于移动设备web开发的一款插件.像缩放.下拉刷新.滑动切换等移动应用上常见的一些效果都可以轻松实现. 现在最新版本是5.X,官网这里:http://iscrolljs.com/ ...

  4. 解决ListView滑动时卡的问题,实现异步加载图片解决

    ListView是最为常见的空间之一,现在的应用的呈现形式大多数都需要用到ListView来呈现,以列表的方式最直观最便于操作. 那么在使用的过程中大家一定使用adapter适配器来匹配这个ListV ...

  5. 关于使用Iscroll.js异步加载数据后不能滑动到最底端的问题解决方案

    关于使用Iscroll.js异步加载数据后不能滑动到最底端,拉到最下边又弹回去的问题困扰了我老半天,相信很多朋友都遇到了.我刚好不小心解决了,和大家分享一下.由于各种忙,下边就直接上代码吧. (前提是 ...

  6. easyui datagrid 异步加载数据时滚动条有时会自动滚到最底部的问题

    在使用easyui 的datagrid异步加载数据时发现滚动条有时会自动滚到最底部.经测试发现,如果加载数据前没有选中行则不会出现这个问题.这样我们可以在重新异步加载数据前取消选中行就可以避免这个问题 ...

  7. 高仿优酷Android客户端图片左右滑动(自动切换)

    本例是用ViewPager去做的实现,支持自动滑动和手动滑动,不仅优酷网,实际上有很多商城和门户网站都有类似的实现: 具体思路: 1. 工程中需要添加android-support-v4.jar,才能 ...

  8. springboot+layui实现PC端用户的增删改查 & 整合mui实现app端的自动登录和用户的上拉加载 & HBuilder打包app并在手机端下载安装

    springboot整合web开发的各个组件在前面已经有详细的介绍,下面是用springboot整合layui实现了基本的增删改查. 同时在学习mui开发app,也就用mui实现了一个简单的自动登录和 ...

  9. tab切换-自动、点击、内容变换

    <div class="tab">                    <ul class="pics">               ...

随机推荐

  1. http长短连接和长短轮询

    http长连接 http长连接是指http的请求头和响应头的均有connection: keep-alive的请求,也就是客户端和服务端均为keep-alive的请求. 实际上,http是请求/响应式 ...

  2. Cookies设置,获取,删除

    之前的博客,整理了下Session的存储方式和原理http://www.cnblogs.com/chinaagan/p/3200456.html. 本篇再次整理下Cookies的使用和原理. 参考博客 ...

  3. Page_Load与Page_PreRender的执行顺序

    原文发布时间为:2009-10-25 -- 来源于本人的百度文章 [由搬家工具导入] Page_PreRender 服务器控件将要呈现给其包含的 控件时发生。简单的理解为page中的控件渲染调用此事件 ...

  4. 遍历页面所有的Checkbox,显示选中的ID

    原文发布时间为:2009-04-13 -- 来源于本人的百度文章 [由搬家工具导入] 1、 foreach (Control objCtrl in this.Page.Controls[3].Cont ...

  5. [LeetCode] Longest Common Prefix 字符串公有前序

    Write a function to find the longest common prefix string amongst an array of strings. Hide Tags Str ...

  6. Eclipse中的android项目前面有叹号 (转)

    问题描述:在Eclipse中导入一个项目,在项目名上有感叹号出现,基本上是由于build path的问题. 解决方法: 在项目上右击-->build path -> configure b ...

  7. android中与Adapter相关的控件----ViewFlipper

    ViewFlipper(翻转视图) 一.ViewFlipper是一个多页面管理的控件,与ViewPager不同,ViewPager的是一页一页的的,而ViewFlipper则是一层一层的.图片轮播或者 ...

  8. (21)python lambda表达式

    lambda表达式是一个匿名函数 通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用 最简单的例子 add = lambda x,y : x + y print add(3,5) #out ...

  9. 北冥有 Data,其名为鲲,鲲之大,一个 MySQL 放不下!

    千万量级的数据,用 MySQL 要怎么存? 初学者在看到这个问题的时候,可能首先想到的是 MySQL 一张表到底能存放多少条数据? 根据 MySQL 官方文档的介绍,MySQL 理论上限是 (232) ...

  10. Jenkins集成java非maven/ant项目的打包思路

    打包的思路如下: 1.使用javac命令对代码进行编译,比如递归编译整个项目的java代码.(注意:需要一一对应引用的jar包) 2.输出并整理war包的文件夹结构目录,参考:http://www.c ...