【Android】首页图片轮播效果(淘宝、京东首页广告效果)

目前很多APP中都有这个图片轮播的功能,项目中也时常会用到,图片轮播一般是在用户不主动进行切换的时候每隔一段时间进行自动切换,用户主动切换时停止自动切换,手指离开时重新计时开始轮播,下面我们就来实现这个功能,功能效果图如下:

这里写图片描述

实现原理:

  • Handler.sendEmptyMessageDelayed(what, DELAYTIME);来进行自动轮播;
  • 监听onTouch事件监听来控制开启和停止轮播;
  • ImageLoader来加载网络图片显示;

1.在activity_main.xml中添加控件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:CircleIndicator="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="180dp" >

        <android.support.v4.view.ViewPager
            android:id="@+id/banner_pager"
            android:layout_width="wrap_content"
            android:layout_height="match_parent" >
        </android.support.v4.view.ViewPager>

        <!-- 指示器 -->

        <LinearLayout
            android:id="@+id/banner_pointer_group"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="10dp"
            android:orientation="horizontal" >
        </LinearLayout>
    </RelativeLayout>

</RelativeLayout>

2.新建实体类BannerEntity

public class BannerEntity implements Serializable
{
    private static final long serialVersionUID = 3250428319336562246L;

    private int id;
    private String img;
    private String url;
    private String jumps;

    public int getId()
    {
        return id;
    }

    public void setId(int id)
    {
        this.id = id;
    }

    public String getImg() {
        return img;
    }

    public void setImg(String img) {
        this.img = img;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getJumps() {
        return jumps;
    }

    public void setJumps(String jumps) {
        this.jumps = jumps;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        BannerEntity other = (BannerEntity) obj;
        if (id != other.id)
            return false;
        return true;
    }

    @Override
    public String toString()
    {
        return "BannerEntity [img=" + img + ", id=" + id + ", url=" + url + ",jumps="+jumps + "]";
    }
}

3.构建自己的PagerAdaper

代码中注释比较详细,有问题欢迎交流讨论。

public class AdatperBanner extends PagerAdapter implements ImageLoadingListener, OnPageChangeListener
{
    /**
     * 切换间隔时间
     */
    private static final long DELAYTIME = 3000;

    private static final int MSG_NEXT = 1;

    /**
     * 默认banner个数
     */
    private static final int DEFAULT_COUNT = 1;

    /**
     * 无数据时默认指定一条数据
     */
    private BannerEntity defaultBanner;

    private Context context;

    /**
     * page切换时的监听
     */
    private OnPageListener pageListener;

    /**
     * 数据源
     */
    private List<BannerEntity> data = new ArrayList<BannerEntity>();

    private ViewPager pager;

    private Handler postHandler = new Handler()
    {
        public void handleMessage(android.os.Message msg)
        {
            if (pager != null)
            {
                int curPage = pager.getCurrentItem();
                if (curPage == (getCount() - 1))
                    pager.setCurrentItem(0);
                else
                    pager.setCurrentItem(++curPage);
            }

            cancelDelayPlay();
            postHandler.sendEmptyMessageDelayed(MSG_NEXT, DELAYTIME);
        };
    };

    public AdatperBanner(ViewPager pager)
    {
        this.pager = pager;
        pager.setOnPageChangeListener(this);
        defaultBanner = new BannerEntity();
    }

    public AdatperBanner(ViewPager pager, OnPageListener listener, Context context)
    {
        this(pager);
        pageListener = listener;
        this.context = context;
    }

    /**
     * <添加数据,并刷新界面>
     * @param data
     * @see [类、类#方法、类#成员]
     */
    public void setDataSource(List<BannerEntity> data)
    {
        this.data.clear();
        if (data != null && !data.isEmpty())
            this.data.addAll(data);
        checkData();
        notifyDataSetChanged();
        pager.setCurrentItem(1);
        startDelayPlay();
    }

    public void setDataSource(BannerEntity data)
    {
        if (data == null)
            return;
        this.data.clear();
        this.data.add(data);
        checkData();
        notifyDataSetChanged();
    }

    /**
     * 校验数据
     * 备注:数据至少一个,如果数据源空,这里需要填补默认数据
     */
    private void checkData()
    {
        if (data.isEmpty())
            data.add(defaultBanner);
    }

    /**
     * 开始自动切换
     * @see [类、类#方法、类#成员]
     */
    public void startDelayPlay()
    {
        //如果数据只有一个或者数据为null,跳出方法
        if (data == null || data.size() < 2)
            return;
        cancelDelayPlay();
        postHandler.sendEmptyMessageDelayed(MSG_NEXT, DELAYTIME);
    }

    /**
     * 撤销自动切换
     * @see [类、类#方法、类#成员]
     */
    public void cancelDelayPlay()
    {
        if (postHandler != null)
            postHandler.removeCallbacksAndMessages(null);
    }

    /**
     * 重写getItemPosition()方法,当调用notifyDataSetChanged时,让getItemPosition方法人为的返回POSITION_NONE,从而达到强迫viewpager重绘所有item的目的。
     * @see android.support.v4.view.PagerAdapter#getItemPosition(java.lang.Object)
     */
    @Override
    public int getItemPosition(Object object)
    {
        return PagerAdapter.POSITION_NONE;
    }

    @Override
    public int getCount()
    {
        return ((data == null || data.isEmpty()) ? DEFAULT_COUNT : data.size()) + 2;
    }

    /**
     * <获取实际的个数>
     * @return
     * @see [类、类#方法、类#成员]
     */
    public int getActualCount()
    {
        return getCount() - 2;
    }

    /**
     * <获取当前的position>
     * @param position
     * @return
     * @see [类、类#方法、类#成员]
     */
    public int getActualDataIndex(int position)
    {
        int tempos = position - 1;
        if (position == 0)
            tempos = data.size() - 1;
        else if (position == getCount() - 1)
            tempos = 0;
        return tempos;
    }

    @Override
    public boolean isViewFromObject(View view, Object object)
    {
        return view == object;
    }

    @Override
    public Object instantiateItem(final ViewGroup container, int position)
    {
        ImageView img = (ImageView)LayoutInflater.from(container.getContext()).inflate(R.layout.ui_home_banner_adapter, null);
        container.addView(img);

        if (data != null && !data.isEmpty())
        {
            final BannerEntity item = data.get(getActualDataIndex(position));
            if (item != null && !TextUtils.isEmpty(item.getImg()))
            {
                ImageLoader.getInstance().displayImage(item.getImg(), img);// 网络图片下载与显示
                img.setOnClickListener(new OnClickListener()
                {
                    @Override
                    public void onClick(View v)
                    {
                        String url = item.getUrl();
                        if (!TextUtils.isEmpty(url))
                        {
                            Toast.makeText(context, url, Toast.LENGTH_SHORT).show();
                        }
                    }
                });
            }
        }

        return img;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object)
    {
        if (object instanceof ImageView)
            container.removeView((ImageView)object);
    }

    @Override
    public void onLoadingCancelled(String arg0, View arg1)
    {

    }

    @Override
    public void onLoadingComplete(String arg0, View arg1, Bitmap arg2)
    {

    }

    @Override
    public void onLoadingFailed(String arg0, View arg1, FailReason arg2)
    {

    }

    @Override
    public void onLoadingStarted(String arg0, View arg1)
    {

    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
    {

    }

    @Override
    public void onPageSelected(int position)
    {
        if (getCount() < 3)
            return;
        if (position == 0)
            pager.setCurrentItem(getCount() - 2, false);
        else if (position == getCount() - 1)
            //如果是最大页数,切换到第一页
            pager.setCurrentItem(1, false);

        if (pageListener != null)
            //更新指示器
//            Toast.makeText(context, "position = "+getActualDataIndex(position), Toast.LENGTH_SHORT).show();
            pageListener.onPageChanged(getActualDataIndex(position));
    }

    @Override
    public void onPageScrollStateChanged(int state)
    {
    }

    public interface OnPageListener
    {
        public void onPageChanged(int item);
    }
}

注:适配器中新增了一个回调OnPageListener,用于更新指示器的位置

4.MainActivity关键代码

public class MainActivity extends Activity implements OnPageListener
{
    private ViewPager viewPager;

    /**
     * 适配器
     */
    private AdatperBanner bannerAdatper;

    /**
     * 模拟数据
     */
    private static final String[] IMAGE_LIST = new String[] {"http://img2.3lian.com/2014/c7/25/d/65.jpg", "http://g.hiphotos.baidu.com/zhidao/pic/item/18d8bc3eb13533fa24dfa175aad3fd1f41345b7b.jpg",
        "http://a2.att.hudong.com/76/83/300254181849132325832985580_950.jpg", "http://img2.3lian.com/2014/f4/77/d/68.jpg"};

    private List<BannerEntity> listEntity = new ArrayList<BannerEntity>();

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        initData();
    }

    private void initView()
    {
        viewPager = (ViewPager)findViewById(R.id.banner_pager);
        bannerAdatper = new AdatperBanner(viewPager, this, this);
        viewPager.setAdapter(bannerAdatper);

        // 按下时不继续定时滑动,弹起时继续定时滑动
        viewPager.setOnTouchListener(new View.OnTouchListener()
        {
            @Override
            public boolean onTouch(View v, MotionEvent event)
            {
                switch (event.getAction())
                {
                    case MotionEvent.ACTION_DOWN:
                        // 按住事件发生后执行代码的区域

                    case MotionEvent.ACTION_MOVE:
                        // 移动事件发生后执行代码的区域
                        bannerAdatper.cancelDelayPlay();
                        break;
                    case MotionEvent.ACTION_UP:
                        // 松开事件发生后执行代码的区域
                        bannerAdatper.startDelayPlay();
                        break;
                    default:
                        bannerAdatper.startDelayPlay();
                        break;
                }
                return false;
            }

        });
    }

    /**
     * 初始化模拟数据
     * @see [类、类#方法、类#成员]
     */
    private void initData()
    {
        listEntity.clear();
        for (int i = 0; i < 4; i++)
        {
            BannerEntity bannerEntity = new BannerEntity();
            bannerEntity.setId(i);
            bannerEntity.setImg(IMAGE_LIST[i]);
            bannerEntity.setJumps("");
            bannerEntity.setUrl("www.baidu.com");
            listEntity.add(bannerEntity);
        }
        bannerAdatper.setDataSource(listEntity);
    }

    /**
     * <动态添加指示器>
     * @param currentIndex
     * @see [类、类#方法、类#成员]
     */
    private void updateBannerPoints(int currentIndex)
    {
        if (bannerAdatper == null)
            return;
        LinearLayout group = (LinearLayout)findViewById(R.id.banner_pointer_group);
        if (null == group)
            return;
        int pointCount = group.getChildCount();
        int deepCount = bannerAdatper.getActualCount() - pointCount;
        //需要添加的话就添加指示器小点
        if (deepCount > 0)
        {
            for (int i = 0; i < deepCount; i++)
            {
                ImageView iv = (ImageView)LayoutInflater.from(MainActivity.this).inflate(R.layout.ui_home_fragment_main_banner_point, group, false);

                if (null != iv)
                    group.addView(iv);
            }
        }
        else if (deepCount < 0)
        {
            for (int i = 0; i < Math.abs(deepCount); i++)
            {
                group.removeViewAt(i);
            }
        }

        for (int i = 0; i < group.getChildCount(); i++)
        {
            View point = group.getChildAt(i);
            if (i == currentIndex)
                point.setSelected(true);
            else
                point.setSelected(false);
        }
    }

    @Override
    public void onPageChanged(int item)
    {
        updateBannerPoints(item);
    }
}

——————–基本代码如上所述,各位看官可根据实际需求做适量修改!


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值