广告banner:手动滑动切换,自动切换,点击跳转,异步加载网络图片

效果图:

该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);
    }
原文地址:https://www.cnblogs.com/xgjblog/p/4226972.html