Android 輪播圖的實現

MarianaPham 8年前發布 | 15K 次閱讀 安卓開發 Android開發 移動開發

環境準備

開發環境

  • Android Studio 2.2.1

  • JDK1.7

  • API 24

  • Gradle 2.2.1

開發開始

先上效果預覽

效果預覽

案例分析

這個案例網上也很多, 質量參差不齊, 我也就根據自己的理解來分析分析需要實現的幾個功能點:

  • 輪播圖有n張圖片和相對應的n個小圓點(指示器 indicator) 實現聯動

  • 除了可以手動滑動外, 也可以自動滾動(輪播) 可以考慮使用Handler實現

  • 實現無限輪回滾動

  • 當手指按下圖片后不再自動滾動

根據上述分析進行開發

接下來搭建布局

activity_main.xml

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="

<LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:layout_marginBottom="275dp">
    <FrameLayout

        android:layout_width="match_parent"
        android:layout_height="220dp">
        <!--輪播圖位置-->
        <android.support.v4.view.ViewPager
            android:id="@+id/live_view_pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
        <!--右下角小圓點-->
        <LinearLayout
            android:layout_marginRight="5dp"
            android:layout_gravity="bottom|right"
            android:id="@+id/live_indicator"
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="10dp"/>
    </FrameLayout>
</LinearLayout>

</RelativeLayout></code></pre>

指示器 小點繪制文件

indicator_select.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="oval">
    <size
        android:width="20dp"
        android:height="20dp"/>
    <solid android:color="#c213b7"/>
</shape>

indicator_no_select.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="oval">
    <size
        android:width="20dp"
        android:height="20dp"/>
    <solid android:color="#fff"/>
</shape>

ViewPager的實現

MyPagerAdapter.java

public class MyPagerAdapter extends PagerAdapter {

public static final int MAX_SCROLL_VALUE = 10000;

private List<ImageView> mItems;
private Context mContext;
private LayoutInflater mInflater;

public MyPagerAdapter(List<ImageView> items, Context context) {
    mContext = context;
    mInflater = LayoutInflater.from(context);
    mItems = items;
}

/**
 * @param container
 * @param position
 * @return 對position進行求模操作
 * 因為當用戶向左滑時position可能出現負值,所以必須進行處理
 */
@Override
public Object instantiateItem(ViewGroup container, int position) {
    View ret = null;

    //對ViewPager頁號求摸取出View列表中要顯示的項
    position %= mItems.size();
    Log.d("Adapter", "instantiateItem: position: " + position);
    ret = mItems.get(position);
    //如果View已經在之前添加到了一個父組件,則必須先remove,否則會拋出IllegalStateException。
    ViewParent viewParent = ret.getParent();
    if (viewParent != null) {
        ViewGroup parent = (ViewGroup) viewParent;
        parent.removeView(ret);
    }
    container.addView(ret);

    return ret;
}
/**
 * 由于我們在instantiateItem()方法中已經處理了remove的邏輯,
 * 因此這里并不需要處理。實際上,實驗表明這里如果加上了remove的調用,
 * 則會出現ViewPager的內容為空的情況。
 *
 * @param container
 * @param position
 * @param object
 */
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    //警告:不要在這里調用removeView, 已經在instantiateItem中處理了
}


@Override
public int getCount() {
    int ret = 0;
    if (mItems.size() > 0) {
        ret = MAX_SCROLL_VALUE;
    }
    return ret;
}

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

}</code></pre>

Note: 一定不要在destroyItem中再調用removeView了, 因為咱們已經instantiateItem中做了處理

在MainActivity.java中給ViewPager設置Adapter

mItems = new ArrayList<>();
mViewPager.setAdapter(mAdapter);

addImageView(); mAdapter.notifyDataSetChanged();</code></pre>

private void addImageView(){
    ImageView view0 = new ImageView(this);
    view0.setImageResource(R.mipmap.pic0);
    ImageView view1 = new ImageView(this);
    view1.setImageResource(R.mipmap.pic1);
    ImageView view2 = new ImageView(this);
    view2.setImageResource(R.mipmap.pic2);

view0.setScaleType(ImageView.ScaleType.CENTER_CROP);
view1.setScaleType(ImageView.ScaleType.CENTER_CROP);
view2.setScaleType(ImageView.ScaleType.CENTER_CROP);

mItems.add(view0);
mItems.add(view1);
mItems.add(view2);

}</code></pre>

Note: 因為咱們做的是Demo, 所以我們傳入的是一個ImageView的集合, 真正開發時, 需要傳入含有圖片url的實體類, 在Adapter中可以使用加載圖片的類庫加載

實現右下角指示器

添加指示器

在onCreate中添加

//獲取指示器(下面三個小點)
mBottomLiner = (LinearLayout) findViewById(R.id.live_indicator);
//右下方小圓點
mBottomImages = new ImageView[mItems.size()];
for (int i = 0; i < mBottomImages.length; i++) {
    ImageView imageView = new ImageView(this);
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(20, 20);
    params.setMargins(5, 0, 5, 0);
    imageView.setLayoutParams(params);
    //如果當前是第一個 設置為選中狀態
    if (i == 0) {
        imageView.setImageResource(R.drawable.indicator_select);
    } else {
        imageView.setImageResource(R.drawable.indicator_no_select);
    }
    mBottomImages[i] = imageView;
    //添加到父容器
    mBottomLiner.addView(imageView);
}

實現聯動

添加ViewPager的監聽事件, 實現ViewPager.OnPageChangeListener接口

mViewPager.addOnPageChangeListener(this);

回調事件

///////////////////////////////////////////////////////////////////////////
// ViewPager的監聽事件
///////////////////////////////////////////////////////////////////////////
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

}

@Override public void onPageSelected(int position) {

currentViewPagerItem = position;
if (mItems != null) {
    position %= mBottomImages.length;
    int total = mBottomImages.length;

    for (int i = 0; i < total; i++) {
        if (i == position) {
            mBottomImages[i].setImageResource(R.drawable.indicator_select);
        } else {
            mBottomImages[i].setImageResource(R.drawable.indicator_no_select);
        }
    }
}

}

@Override public void onPageScrollStateChanged(int state) {

}</code></pre>

實現自動滾動

在mBottomImages初始化之后 開啟一個線程 進行定時發送一個空消息給Handler處理, 由Handler決定切換到下一頁

//讓其在最大值的中間開始滑動, 一定要在 mBottomImages初始化之前完成
int mid = MyPagerAdapter.MAX_SCROLL_VALUE / 2;
mViewPager.setCurrentItem(mid);
currentViewPagerItem = mid;

//定時發送消息 mThread = new Thread(){ @Override public void run() { super.run(); while (true) { mHandler.sendEmptyMessage(0); try { Thread.sleep(MainActivity.VIEW_PAGER_DELAY); } catch (InterruptedException e) { e.printStackTrace(); } }

}

}; mThread.start();</code></pre>

自定義Handler

///////////////////////////////////////////////////////////////////////////
// 為防止內存泄漏, 聲明自己的Handler并弱引用Activity
///////////////////////////////////////////////////////////////////////////
private static class MyHandler extends Handler {
    private WeakReference<MainActivity> mWeakReference;

public MyHandler(MainActivity activity) {
    mWeakReference = new WeakReference<MainActivity>(activity);
}

@Override
public void handleMessage(Message msg) {
    super.handleMessage(msg);
    switch (msg.what) {
        case 0:
            MainActivity activity = mWeakReference.get();
            if (activity.isAutoPlay) {

                activity.mViewPager.setCurrentItem(++activity.currentViewPagerItem);
            }

            break;
    }

}

}</code></pre>

Note: 其中isAutoPlay是一個用來判斷當前是否是自動輪播的boolean值變量, 主要用于實現我們接下來說的 當手指按下圖片后不再滾動

實現當手指按下圖片后不再滾動

思路: 我們可以考慮對ViewPager的觸摸事件進行監聽, 然后設置一個上節說到的isAutoPlay的boolean變量用來讓Handler判斷是否進行輪播滾動

代碼實現:

ViewPager設置監聽

mViewPager.setOnTouchListener(this);

事件回調

@Override
public boolean onTouch(View v, MotionEvent event) {
    int action = event.getAction();
    switch (action) {
        case MotionEvent.ACTION_DOWN:
            isAutoPlay = false;
            break;
        case MotionEvent.ACTION_UP:
            isAutoPlay = true;
            break;
    }
    return false;
}

注:細心的同學可能會看出來, 我們沒有單獨說 無限循環 如何實現, 其實, 它的實現已經隱藏在了代碼中, 在這里我簡單的說一下思路:

給ViewPager的條目個數設置個較大值, 該案例中為10000, 然后我們剛進入時選中的位置為 10000/2=5000, 也就是說我們可以向左或向右滑動約5000多張圖片, 但這是不現實的, 所以就給用戶造成了無限循環的假象

 

 

來自:http://www.jianshu.com/p/24b30a3d052f

 

 本文由用戶 MarianaPham 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!