Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android輪播圖的實現

Android輪播圖的實現

編輯:關於Android編程

這幾天看了《Android開發藝術探索》這本書真的是挺不錯的,學了自定義View之後打算動手實踐一個輪播圖控件,網上有很多實現的方法,我最後實現起來跟他們也基本上都是大同小異,主要我也是為了練練動手能力。先來個效果圖,圖片是在百度搜的正經圖片

輪播圖效果

分析

實現輪播圖的方式大體上我看到了三種,一是使用安卓的Gallery控件來實現,二是使用HorizontalScrollView,三是使用ViewPager來實現,Gallery控件現在已經不推薦使用了,在源碼中我們也看到了,現在推薦使用的是後面的兩種,而我實現的方式選擇了第三種ViewPager,整個實現流程可以大致分為一下三個部分:

1.AutoSlideView 也是輪播圖控件的實現,這裡我的控件繼承自ViewGoup的FrameLayout子類,同時需要一個xml的布局文件來定義控件的樣式,裡面主要包括了ViewPager和下面指示器圓點的容器。

2.Adapter的實現,需要給AutoSlideView中的ViewPager指定適配器,來指定輪播圖中需要展示出來的View控件,同時也需要每個具體ItemView的xml布局文件,ViewPager的Adapter和ListView的Adapter使用起來思想上都不會相差太多。

3.SlideInfo 數據類的設計,因為實際的開發中輪播圖需要的圖片之類的信息是需要從服務器上拉取的,需要對數據進行一次封裝。

SlideInfo類的實現

//由於我這個不涉及到具體的業務,所以這個類僅僅只是設置了一個圖片的URL
public class SlideInfo {
    String image_url ="dd";

    public SlideInfo(){}
    public SlideInfo(String url){
        this.image_url = url;
    }

    public String getImage_url() {
        return image_url;
    }
}

Adapter的實現

首先PagerAdapter使用時需要重寫四個方法,考慮到如果輪播圖實用在不同的界面上,可能會有多種不同的ItemView 如果每次都重寫一個PagerAdapter 會造成大量重復代碼的編寫,可以考慮編寫一個抽象的適配器,把獲取View單獨讓子類去實現

AutoSlideViewAdapterBase類

package com.humorousz.myapplication.adapter;

import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by zhangzhiquan on 2016/7/14.
 */
public abstract class AutoSlideViewAdapterBase extends PagerAdapter {

    private List mList;

    public AutoSlideViewAdapterBase() {
        mList = new ArrayList<>();
    }


    @Override
    public int getCount() {
        /**
         * 這裡需要說明一點,因為我們需要循環滑動
         * 但是ViewPager本身並不支持,所以我們需要給
         * ViewPager的頁面設置成int最大值造成循環滑動
         * 的假象,具體可以在網上搜索ViewPager循環滑動
         * 可能會有更好的實現方式
         */
        return Integer.MAX_VALUE;
    }

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

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View v;
        /**
        * 我在實驗的時候發現有時候size和position的差值大於一
        * 造成越界,所以在這添加從size到實際位置的View
        */
        if (mList.size() <= (position % getSize())) {
           for(int i=mList.size() ; i<=position%getSize();++i){
               mList.add(getView(container,i));
           }
        }
        v = mList.get(position % getSize());
        if(v.getParent() != null){
            container.removeView(v);
        }
        container.addView(v);
        return v;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView(mList.get(position % getSize()));
    }

    /**
    *抽象的方法,用於獲取實際需要顯示的View
    */
    public abstract View getView(ViewGroup container,int position);

    /**
    *用於獲取實際ItemView的數量
    */
    public abstract int getSize();
}

SlideAdapter類

package com.humorousz.myapplication.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import com.humorousz.myapplication.R;
import com.humorousz.myapplication.data.SlideInfo;
import com.nostra13.universalimageloader.core.ImageLoader;

import java.util.List;

/**
 * Created by zhangzhiquan on 2016/7/14.
 */
public class SlideAdapter extends AutoSlideViewAdapterBase {

    List mSlides;

    Context mContext;

    public SlideAdapter(Context context,List list){
        mContext = context;
        mSlides = list;
    }

/**
* 實現了獲取Viwe的方法
* 使用了ImageLoder來獲取圖片顯示到ImageView上
*/
    @Override
    public View getView(ViewGroup container,int position) {
        ImageView imageView;
        View v = LayoutInflater.from(mContext)
                .inflate(R.layout.layout_slide_item,null);
        imageView = (ImageView)v.findViewById(R.id.image);
        ImageLoader.getInstance().
                displayImage(mSlides.get(position).getImage_url(),imageView);
        return v;
    }

    @Override
    public int getSize() {
        return mSlides.size();
    }

}

XML文件

itemView的xml文件:layout_slide_item




    

整個AutoSlideView的xml:layout_auto_slide_view




    

    

        
    

AutoSlideView類的實現

package com.humorousz.myapplication.widget;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.humorousz.myapplication.R;
import com.humorousz.myapplication.adapter.AutoSlideViewAdapterBase;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by zhangzhiquan on 2016/7/14.
 */
public class AutoSlideView extends FrameLayout implements ViewPager.OnPageChangeListener {

    private ViewPager mViewsContainer;

    private LinearLayout mPointContainer;

    private AutoSlideViewAdapterBase mAdapter;

    private int mPointCount;

    private ImageView[] mPoints;

    private int mLastPos;

    private Timer mTimer;

    private TimerTask mTask;

    private boolean isTouch = false;

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            mViewsContainer.setCurrentItem(mViewsContainer.getCurrentItem() + 1);
        }
    };

    public AutoSlideView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        init();
    }


    private void init() {
        mViewsContainer = (ViewPager) findViewById(R.id.views_container);
        mPointContainer = (LinearLayout) findViewById(R.id.point_container);
        mViewsContainer.addOnPageChangeListener(this);
    }

    public void setData(AutoSlideViewAdapterBase adapter) {
        mAdapter = adapter;
        mPointCount = mAdapter.getSize();
        mViewsContainer.setAdapter(mAdapter);
        initPoint();
        /**
        *這樣做是可以保證初始情況下可以向左滑動,
        *但是如果有毅力的話,還是能左滑到盡頭的
        *這個方法也是在別人的博客裡看見的
        */
        mViewsContainer.setCurrentItem(mPointCount * 100);
        startAutoSlide();
    }

    private void initPoint() {
        if (mPointCount == 0)
            return;
        mPoints = new ImageView[mPointCount];
        for (int i = 0; i < mPointCount; i++) {
            ImageView view = new ImageView(getContext());
            view.setImageResource(R.mipmap.point_normal);
            mPointContainer.addView(view);
            mPoints[i] = view;
        }
        if (mPoints[0] != null) {
            mPoints[0].setImageResource(R.mipmap.point_selected);
        }
        mLastPos = 0;

    }

    private void changePoint(int curPos) {
        if (mLastPos == curPos)
            return;
        mPoints[curPos].setImageResource(R.mipmap.point_selected);
        mPoints[mLastPos].setImageResource(R.mipmap.point_normal);
        mLastPos = curPos;

    }

    private void startAutoSlide() {
        if (mTimer == null)
            mTimer = new Timer();
        if (mTask != null) {
            mTask.cancel();
            mTask = null;
        }
        mTask = new TimerTask() {
            @Override
            public void run() {
            /** 
            *如果正在觸摸就暫時結束自動滑動
            */
                if (isTouch) {
                    return;
                }
                handler.sendEmptyMessage(0x00);
            }
        };

        mTimer.schedule(mTask, 300, 3000);
    }

    public void cancelAutoSlide() {
        if (mTask != null) {
            mTask.cancel();
            mTask = null;
        }
    }


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

    }

    @Override
    public void onPageSelected(int position) {
        changePoint(position % mPointCount);
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }


    /**
    *isTouch變量用於是否用戶在點擊或者滑動
    *可根據這個標記來暫時停止自動滑動
    */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                isTouch = true;
                break;
            case MotionEvent.ACTION_UP:
                isTouch = false;
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

}

在MainActivity中的使用

package com.humorousz.myapplication;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.ViewGroup;

import com.humorousz.myapplication.adapter.SlideAdapter;
import com.humorousz.myapplication.data.SlideInfo;
import com.humorousz.myapplication.widget.AutoSlideView;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    AutoSlideView mAutoSlideView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ImageLoader.getInstance().
                init(ImageLoaderConfiguration.createDefault(this));
        mAutoSlideView = (AutoSlideView) LayoutInflater.from(this).
                inflate(R.layout.layout_auto_slide_view,null);
        List list = new ArrayList<>();
        list.add(new SlideInfo("http://g.hiphotos.baidu.com/image/pic/item/" +
                "f3d3572c11dfa9ecfc13ccc066d0f703918fc12c.jpg"));
        list.add(new SlideInfo("http://img5.imgtn.bdimg.com/it/" +
                "u=1944136054,210950671&fm=21&gp=0.jpg"));
        list.add(new SlideInfo("http://img05.tooopen.com/images/" +
                "20140728/sy_67568071862.jpg"));
        list.add(new SlideInfo("http://img4.imgtn.bdimg.com/it/" +
                "u=652859225,1742711825&fm=21&gp=0.jpg"));
        list.add(new SlideInfo("http://img.taopic.com/uploads/" +
                "allimg/140517/240456-14051G5163057.jpg"));
        mAutoSlideView.setData(new SlideAdapter(this, list));
        addContentView(mAutoSlideView,
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 
                        ViewGroup.LayoutParams.WRAP_CONTENT));

    }
}

ok,到此整個控件就完成了,還有不足的地方就是,控件的高度沒有能夠在使用時設置,可以進一步將AutoSlideView進行抽象然後將高度進行設置,也可以在使用時設置LayoutParams,wrap_content應該不是很常用,因為實際開發過程中布局的寬度設計同學都會給標注好的

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved