Android仿餓了么首頁導航欄(ViewPager)

klxklx 7年前發布 | 26K 次閱讀 ViewPager Android開發 移動開發

1、需求分析

在餓了么首頁中我們能看到這樣的布局(如下圖)。紅框內是一個可以左右滑動的頁面,每一個頁面類似于九宮格,都有可供點擊圖標。對于這樣的布局,我在網上找了很久都沒有找到相關的名稱,所以我這里暫時叫它導航頁吧。

最近公司的項目就要求我實現一個這樣的布局,但是我們的圖標并不是想餓了么這樣是固定的,所以在餓了么的布局上還要加一個效果:在圖標數目無法排滿兩行時,就只顯示一行。比如說,我們每一頁最多可以顯示兩行和四列,當圖標的總數目小于或等于4個時就只顯示出一行,第二行就不要了。這樣頁面就不至于留出太多的空白。

先梳理一下我們要實現的效果:

  1. 大體的框架是一個可以左右滑動的頁面;

  2. 每一頁為兩行四列的矩陣;

  3. 底部有和頁面數目相等的導航點,且滑動到某個頁面時,相應的導航點會改變顏色;

  4. 單選事件:選中圖標后,圖標變為完全不透明。

明白需求之后,我們穿越時空看看最后實現后的布局:

圖片資源大家可以在我源碼中找到。

2、實現思路

我們已經分析了需求,現在就來分析一下怎么實現。

必須事先說明一下,我的實現方法比較暴力,也比較占資源,所以大家要是有更好的方法的話歡迎留言告訴我,我們互相學習。

首先,這是一個左右滑動的頁面,所以我們可以考慮使用ViewPager我們每個頁面有8個圖標,也就是8個item。在圖標的數目在4以下時就只顯示第一行,所以布局上我們可以將四個item作為一行放置到橫向的線性布局中,當第二行沒有圖標時就讓它消失。

ViewPager中的每一頁的布局都是一樣,所以我們可以對其復用:將圖標分組,每8個為一組(余下的不到八頁也歸為一組),每一組即為一頁。每次滑動的頁面時就加載布局,填充圖標和文字。

下面的導航點就比較簡單了,可以使用ViewPager的滑動監聽事件進行監聽,滑動到選中的頁面時就改變導航點的顏色。

至于透明,我們只需要記錄圖標的選中狀態,然后改變透明度即可。

3、編寫布局

接下來就讓我們創建項目,編寫頁面布局吧。

在Android Studio中創建一個NavigationPager項目,MainActivity的布局如下:

activity_main.xml

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

<com.lindroid.navigationpager.CustomViewPager
    android:background="@android:color/white"
    android:id="@+id/vp_navigation"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >
</com.lindroid.navigationpager.CustomViewPager>

<LinearLayout
    android:background="@android:color/white"
    android:layout_gravity="center_horizontal"
    android:gravity="center"
    android:id="@+id/ll_dots"
    android:orientation="horizontal"
    android:layout_below="@+id/vp_navigation"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
</LinearLayout>

</LinearLayout></code></pre>

MainActivity的主布局是一個縱向的線性布局,上面一個ViewPager,下面一個橫向的線性布局,用于放置導航點。這里得說一下ViewPager的特性,在不指定特定高度的情況下,ViewPager的高度是默認填充整個父布局的,我們顯然不希望這樣,畢竟我們還要分一行和兩行兩種情況呢。所以這里我在這里使用了一個可以自適應高度的自定義ViewPager:

CustomViewPager

/**

  • Created by Lindroid on 2017/3/20.
  • 自適應高度的ViewPager */

public class CustomViewPager extends ViewPager { public CustomViewPager(Context context) { super(context); }

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

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    int height = 0;
    for (int i = 0; i < getChildCount(); i++) {
        View child = getChildAt(i);
        child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        int h = child.getMeasuredHeight();
        if (h > height)
            height = h;
    }

    heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

}</code></pre>

頁面的布局(也就是ViewPager的子布局)可以拆分成兩個橫向排列的布局:

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

<LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <include layout="@layout/layout_line1"/>
    <include layout="@layout/layout_line2"/>

</LinearLayout>

</LinearLayout></code></pre>

layout_line1.xml和layout_line2.xml分別為第一行和第二行的布局,下面是layout_line1.xml的布局。layout_line2.xml除了控件的id名不同之外,其他的都一樣,這里就不貼出來了。

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

<LinearLayout

    android:id="@+id/ll_item1"
    android:gravity="center"
    android:padding="10dp"
    android:orientation="vertical"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="wrap_content">

    <ImageView

        android:id="@+id/iv_icon1"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="@mipmap/ic_launcher_round" />

    <TextView
        android:id="@+id/tv_name1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="圖標名稱" />
</LinearLayout>

<LinearLayout
    android:id="@+id/ll_item2"
    android:gravity="center"
    android:padding="10dp"
    android:orientation="vertical"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/iv_icon2"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="@mipmap/ic_launcher_round" />

    <TextView
        android:id="@+id/tv_name2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="圖標名稱" />
</LinearLayout>

<LinearLayout
    android:id="@+id/ll_item3"
    android:gravity="center"
    android:padding="10dp"
    android:orientation="vertical"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="wrap_content">

    <ImageView

        android:id="@+id/iv_icon3"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="@mipmap/ic_launcher_round" />

    <TextView
        android:id="@+id/tv_name3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="圖標名稱" />
</LinearLayout>

<LinearLayout
    android:id="@+id/ll_item4"
    android:gravity="center"
    android:padding="10dp"
    android:orientation="vertical"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="wrap_content">

    <ImageView

        android:id="@+id/iv_icon4"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="@mipmap/ic_launcher_round" />

    <TextView
        android:id="@+id/tv_name4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="圖標名稱" />
</LinearLayout>

</LinearLayout></code></pre>

好了,我們所需要的布局都已經編寫完畢,下面就正式開始寫代碼了!

4、編寫代碼

4.1 創建Bean類

創建一個NavigationItemBean類,用于存儲圖標的圖片id、名稱和選中狀態等信息。

public class NavigationItemBean {
    private int iconID;
    private String iconName;
    private boolean isSelected;

public NavigationItemBean(int iconID, String iconName) {
    this.iconID = iconID;
    this.iconName = iconName;
}

public boolean isSelected() {
    return isSelected;
}

public void setSelected(boolean selected) {
    isSelected = selected;
}

public int getIconID() {
    return iconID;
}

public void setIconID(int iconID) {
    this.iconID = iconID;
}

public String getIconName() {
    return iconName;
}

public void setIconName(String iconName) {
    this.iconName = iconName;
}

}</code></pre>

4.2 設置圖標資源

為了提高效率,我在初始化控件時使用了ButterKnife,大家需要它的jar包的話也可以從我的工程中復制粘貼。

public class MainActivity extends AppCompatActivity  {

@Bind(R.id.vp_navigation)
CustomViewPager V*Navigation;
@Bind(R.id.ll_dots)
LinearLayout llDots;
private NavigationAdapter adapter;
private List<NavigationItemBean> itemBeanList = new ArrayList<>();
private List<ImageView> dots = new ArrayList<>();

//圖標id數組
private int[] icons = {R.mipmap.phone,
        R.mipmap.browser,
        R.mipmap.messages,
        R.mipmap.contacts,
        R.mipmap.camera,
        R.mipmap.gallery,
        R.mipmap.calendar,
        R.mipmap.calculator,
        R.mipmap.settings,
        R.mipmap.mail,
        R.mipmap.maps,
        R.mipmap.music,
        R.mipmap.movie};

//圖標名稱數組
private String[] names = {"電話",
        "瀏覽器",
        "信息",
        "聯系人",
        "照相",
        "圖庫",
        "日歷",
        "計算器",
        "設置",
        "郵箱",
        "地圖",
        "音樂",
        "電影"};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.bind(this);
    initData();
}

private void initData() {
    for (int i = 0; i < icons.length; i++) {
        itemBeanList.add(new NavigationItemBean(icons[i], names[i]));
    }
    adapter = new NavigationAdapter(this, itemBeanList, this);
    V*Navigation.setAdapter(adapter);
}

}</code></pre>

先將圖標的id和名稱存儲到兩個數組中,再遍歷數組將資源添加到集合中。

4.3 創建適配器

這一步應該是整個項目中最難的一步了,所以要打起精神來了。先看下面的代碼:

public class NavigationAdapter extends PagerAdapter {
    @Bind(R.id.iv_icon1)
    ImageView ivIcon1;
    @Bind(R.id.tv_name1)
    TextView tvName1;
    @Bind(R.id.ll_item1)
    LinearLayout llItem1;
    @Bind(R.id.iv_icon2)
    ImageView ivIcon2;
    @Bind(R.id.tv_name2)
    TextView tvName2;
    @Bind(R.id.ll_item2)
    LinearLayout llItem2;
    @Bind(R.id.iv_icon3)
    ImageView ivIcon3;
    @Bind(R.id.tv_name3)
    TextView tvName3;
    @Bind(R.id.ll_item3)
    LinearLayout llItem3;
    @Bind(R.id.iv_icon4)
    ImageView ivIcon4;
    @Bind(R.id.tv_name4)
    TextView tvName4;
    @Bind(R.id.ll_item4)
    LinearLayout llItem4;
    @Bind(R.id.iv_icon5)
    ImageView ivIcon5;
    @Bind(R.id.tv_name5)
    TextView tvName5;
    @Bind(R.id.ll_item5)
    LinearLayout llItem5;
    @Bind(R.id.iv_icon6)
    ImageView ivIcon6;
    @Bind(R.id.tv_name6)
    TextView tvName6;
    @Bind(R.id.ll_item6)
    LinearLayout llItem6;
    @Bind(R.id.iv_icon7)
    ImageView ivIcon7;
    @Bind(R.id.tv_name7)
    TextView tvName7;
    @Bind(R.id.ll_item7)
    LinearLayout llItem7;
    @Bind(R.id.iv_icon8)
    ImageView ivIcon8;
    @Bind(R.id.tv_name8)
    TextView tvName8;
    @Bind(R.id.ll_item8)
    LinearLayout llItem8;
    @Bind(R.id.ll_line2)
    LinearLayout llLine2;

private Context context;
private List<NavigationItemBean> itemBeanList;
private List<View> itemViews;
int pages; //總頁數
private View pageView;
private View.OnClickListener onClickListener;

public NavigationAdapter(Context context, List<NavigationItemBean> itemBeanList, View.OnClickListener onClickListener) {
    this.context = context;
    this.itemBeanList = itemBeanList;
    this.onClickListener = onClickListener;
    itemViews = new ArrayList<>();
    initView(itemBeanList);
}
/**
 * 初始化ViewPager的頁面布局
 * @param list
 */
private void initView(List<NavigationItemBean> list) {
    itemViews.clear();
    //計算ViewPager的頁數
    pages = list.size() / 9;
    pages = pages + 1;
    for (int i = 0; i < pages; i++) {
        pageView = View.inflate(context, R.layout.page_navigation, null);
        ButterKnife.bind(this, pageView);
        setPagerViewData(i);
        itemViews.add(pageView);
    }
}
/**
 * 根據頁碼來填充數據
 * @param pageNum
 */
public void setPagerViewData(int pageNum) {
    if (itemBeanList.size() > pageNum * 8 + 0) {
        llItem1.setVisibility(View.VISIBLE);
        tvName1.setText(itemBeanList.get(pageNum * 8 + 0).getIconName());
        ivIcon1.setBackgroundResource(itemBeanList.get(pageNum * 8 + 0).getIconID());
        setIconAlpha(itemBeanList.get(pageNum * 8 + 0).isSelected(), ivIcon1);
    } else {
        llItem1.setVisibility(View.INVISIBLE);
    }

    if (itemBeanList.size() > pageNum * 8 + 1) {
        llItem2.setVisibility(View.VISIBLE);
        tvName2.setText(itemBeanList.get(pageNum * 8 + 1).getIconName());
        ivIcon2.setBackgroundResource(itemBeanList.get(pageNum * 8 + 1).getIconID());
        setIconAlpha(itemBeanList.get(pageNum * 8 + 1).isSelected(), ivIcon2);
    } else {
        llItem2.setVisibility(View.INVISIBLE);
    }

    if (itemBeanList.size() > pageNum * 8 + 2) {
        llItem3.setVisibility(View.VISIBLE);
        tvName3.setText(itemBeanList.get(pageNum * 8 + 2).getIconName());
        ivIcon3.setBackgroundResource(itemBeanList.get(pageNum * 8 + 2).getIconID());
        setIconAlpha(itemBeanList.get(pageNum * 8 + 2).isSelected(), ivIcon3);
    } else {
        llItem3.setVisibility(View.INVISIBLE);
    }

    if (itemBeanList.size() > pageNum * 8 + 3) {
        llItem4.setVisibility(View.VISIBLE);
        tvName4.setText(itemBeanList.get(pageNum * 8 + 3).getIconName());
        ivIcon4.setBackgroundResource(itemBeanList.get(pageNum * 8 + 3).getIconID());
        setIconAlpha(itemBeanList.get(pageNum * 8 + 3).isSelected(), ivIcon4);
    } else {
        llItem4.setVisibility(View.INVISIBLE);
    }

    if (itemBeanList.size() > pageNum * 8 + 4) {
        llItem5.setVisibility(View.VISIBLE);
        tvName5.setText(itemBeanList.get(pageNum * 8 + 4).getIconName());
        ivIcon5.setBackgroundResource(itemBeanList.get(pageNum * 8 + 4).getIconID());
        setIconAlpha(itemBeanList.get(pageNum * 8 + 4).isSelected(), ivIcon5);
    } else {
        llItem5.setVisibility(View.INVISIBLE);
        llLine2.setVisibility(View.GONE);
    }

    if (itemBeanList.size() > pageNum * 8 + 5) {
        llItem6.setVisibility(View.VISIBLE);
        tvName6.setText(itemBeanList.get(pageNum * 8 + 5).getIconName());
        ivIcon6.setBackgroundResource(itemBeanList.get(pageNum * 8 + 5).getIconID());
        setIconAlpha(itemBeanList.get(pageNum * 8 + 5).isSelected(), ivIcon6);
    } else {
        llItem6.setVisibility(View.INVISIBLE);
    }

    if (itemBeanList.size() > pageNum * 8 + 6) {
        llItem7.setVisibility(View.VISIBLE);
        tvName7.setText(itemBeanList.get(pageNum * 8 + 6).getIconName());
        ivIcon7.setBackgroundResource(itemBeanList.get(pageNum * 8 + 6).getIconID());
        setIconAlpha(itemBeanList.get(pageNum * 8 + 6).isSelected(), ivIcon7);
    } else {
        llItem7.setVisibility(View.INVISIBLE);
    }

    if (itemBeanList.size() > pageNum * 8 + 7) {
        llItem8.setVisibility(View.VISIBLE);
        tvName8.setText(itemBeanList.get(pageNum * 8 + 7).getIconName());
        ivIcon8.setBackgroundResource(itemBeanList.get(pageNum * 8 + 7).getIconID());
        setIconAlpha(itemBeanList.get(pageNum * 8 + 7).isSelected(), ivIcon8);
    } else {
        llItem8.setVisibility(View.INVISIBLE);
    }
}

public void setIconAlpha(boolean isSelected, ImageView imageView) {
    if (isSelected) {
        imageView.setAlpha(1.0f);
    } else {
        imageView.setAlpha(0.4f);
    }
}

@Override
public int getCount() {
    return pages;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    container.addView(itemViews.get(position));
    return itemViews.get(position);
}

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

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

}</code></pre>

代碼有點長,但其實不難理解。首先我們創建一個NavigationAdapter繼承于ViewPager專用的PageAdapter,并重寫其中的幾個方法。這里就要注意一個小地方了,getCount方法返回的是ViewPager的item數目,也就是頁數,而不是圖標的數目,可千萬不能搞錯了!

下面我就講解一下比較重要的方法。首先是初始化ViewPager頁面布局的方法initView:

private void initView(List<NavigationItemBean> list) {
        itemViews.clear();
        //計算ViewPager的頁數
        pages = list.size() / 9;
        pages = pages + 1;
        for (int i = 0; i < pages; i++) {
            pageView = View.inflate(context, R.layout.page_navigation, null);
            ButterKnife.bind(this, pageView);
            setPagerViewData(i);
            itemViews.add(pageView);
        }
    }

第4和第5行的代碼是根據圖標的數目來計算ViewPager的頁數,而for循環則是有多少頁我們就調用多少次View.inflate方法去創建布局。這也是 ButterKnife.bind(this, pageView) 要在for循環中執行的原因:我們使用的雖然都是同一個布局文件,但實際每次循環都會創建一個新的布局。

setPagerViewData方法則是給頁面中的每個item填充數據。首先判斷集合中的某一位是否有數據,有的話則設置圖片和文字,反之則隱藏item。里面的代碼基本都一個樣子,我就摘錄其中“最特別”的一段了:

if (itemBeanList.size() > pageNum * 8 + 4) {
            llItem5.setVisibility(View.VISIBLE);
            tvName5.setText(itemBeanList.get(pageNum * 8 + 4).getIconName());
            ivIcon5.setBackgroundResource(itemBeanList.get(pageNum * 8 + 4).getIconID());
            setIconAlpha(itemBeanList.get(pageNum * 8 + 4).isSelected(), ivIcon5);
        } else {
            llItem5.setVisibility(View.INVISIBLE);
            llLine2.setVisibility(View.GONE); //t圖標數不大于4個時讓第二行消失
        }

如果你對于initView方法中for循環從0開始(頁碼的取值從0開始)而不是從1開始感到不解,那么看了setPagerViewData方法之后相信你就會懂了。頁碼為0時,第一頁的第一個item取到的正好是集合的0位元素;頁碼為1時,第二頁的第一個item則是集合中的第8位(1x8+1)元素,這樣,我們就可以根據具體的頁碼來將集合中的元素填充到頁面中。這里別忘了還有高度適應的問題。回頭看看我摘出來的這段代碼,當集合長度不大于4時,我們不僅要隱藏第五個item,而且要讓第二行的布局消失,這時,ViewPager的高度就只有一行了。但你肯定會問,第一頁時去掉第二行沒什么,可以到了第二頁時如果集合元素排不到第二行,第二行也會消失嗎?答案是不會的。ViewPager默認所有頁面的高度都是一致的,就算你在第二頁就去掉了第二行,它的高度也不會隨著改變。

4.4 設置導航點

在MainActivity中,我們創建繪制導航點的方法。導航點是使用xml文件畫的,灰色為未選中,綠色為選中。

private List<ImageView> dots = new ArrayList<>();
    /**

 * 繪制導航點
 */
private void initDot() {
    for (int i = 0; i < (itemBeanList.size() / 9 + 1); i++) {
        Log.e("Tag", itemBeanList.size() + "");
        ImageView imageView = new ImageView(this);
        //創建一個ImageView來放置圓點,并確定ImageView的寬高
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                20, 20);
        params.leftMargin = 10;
        params.rightMargin = 10;
        params.topMargin = 5;
        params.bottomMargin = 10;
        imageView.setLayoutParams(params);
        dots.add(imageView);
        //由于剛進去引導頁時出現的是第一個引導頁,故此時的導航點設置為紅色
        if (i == 0) {
            dots.get(i).setBackgroundResource(R.drawable.dot_green);
        } else {
            dots.get(i).setBackgroundResource(R.drawable.dot_gray);
        }
        llDots.addView(imageView);
    }
}</code></pre> 

導航點的父布局是LinearLayout,所以我們使用LinearLayout中的LayoutParams給導航點設置上下左右的邊距。在onCreate中調用該方法就可以繪制導航點了。因為ViewPager默認顯示的是第一頁,所以我們默認第一個的導航點是選中的。

除此之外,我們還需要讓導航點起到導航的作用。這時候就可以去調用ViewPager的頁面滑動監聽了:

/**
         * 滑動監聽事件
         */
        V*Navigation.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                Log.e("Tag", "position=" + position);
                for (int i = 0; i < dots.size(); i++) {
                    if (i == position) {
                        dots.get(i).setBackgroundResource(R.drawable.dot_green);
                    } else {
                        dots.get(i).setBackgroundResource(R.drawable.dot_gray);
                    }
                }
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

在選中某個頁面時就將對應的導航點改為綠色就可以了。

4.5 圖標的點擊事件

頁面布局中的控件都是在適配器NavigationAdapter中初始化的,為了在MainActivity中能夠實現它們的點擊事件,我們在NavigationAdapter的構造方法中傳入一個View.onClickListener的對象作為參數,只需在MainActivity繼承View.OnClickListener接口,在創建NavigationAdapter時傳入this即可。

當然,我們還需要在NavigationAdapter中讓需要實現點擊事件的控件調用setOnClickListener方法:

private void initListener() {
        llItem1.setOnClickListener(onClickListener);
        llItem2.setOnClickListener(onClickListener);
        llItem3.setOnClickListener(onClickListener);
        llItem4.setOnClickListener(onClickListener);
        llItem5.setOnClickListener(onClickListener);
        llItem6.setOnClickListener(onClickListener);
        llItem7.setOnClickListener(onClickListener);
        llItem8.setOnClickListener(onClickListener);
    }

大家想一想,initListener方法應該在哪里調用呢?這里有一個坑,由于ViewPager的頁面是一頁一頁地繪制的,所以注冊控件的點擊事件也應該在for循環中,為每一頁的控件都注冊一遍:

for (int i = 0; i < pages; i++) {
            pageView = View.inflate(context, R.layout.page_navigation, null);
            ButterKnife.bind(this, pageView);
            setPagerViewData(i);
            itemViews.add(pageView);
            initListener();
        }

好了,現在可以到MainActivity中實現監聽事件了:

@Override
    public void onClick(View v) {
        int pageNum = V*Navigation.getCurrentItem();
        Log.e("Tag", "viewPager.getCurrentItem()=" + V*Navigation.getCurrentItem());
        switch (v.getId()) {
            case R.id.ll_item1:
                Toast.makeText(this, itemBeanList.get(pageNum * 8 + 0).getIconName(), Toast.LENGTH_SHORT).show();
                initSelected();
                itemBeanList.get(pageNum * 8 + 0).setSelected(true);
                adapter.refresh(itemBeanList);
                break;
            case R.id.ll_item2:
                Toast.makeText(this, itemBeanList.get(pageNum * 8 + 1).getIconName(), Toast.LENGTH_SHORT).show();
                initSelected();
                itemBeanList.get(pageNum * 8 + 1).setSelected(true);
                adapter.refresh(itemBeanList);
                break;
            case R.id.ll_item3:
                Toast.makeText(this, itemBeanList.get(pageNum * 8 + 2).getIconName(), Toast.LENGTH_SHORT).show();
                initSelected();
                itemBeanList.get(pageNum * 8 + 2).setSelected(true);
                adapter.refresh(itemBeanList);
                break;
            case R.id.ll_item4:
                Toast.makeText(this, itemBeanList.get(pageNum * 8 + 3).getIconName(), Toast.LENGTH_SHORT).show();
                initSelected();
                itemBeanList.get(pageNum * 8 + 3).setSelected(true);
                adapter.refresh(itemBeanList);
                break;
            case R.id.ll_item5:
                Toast.makeText(this, itemBeanList.get(pageNum * 8 + 4).getIconName(), Toast.LENGTH_SHORT).show();
                initSelected();
                itemBeanList.get(pageNum * 8 + 4).setSelected(true);
                adapter.refresh(itemBeanList);
                break;
            case R.id.ll_item6:
                Toast.makeText(this, itemBeanList.get(pageNum * 8 + 5).getIconName(), Toast.LENGTH_SHORT).show();
                initSelected();
                itemBeanList.get(pageNum * 8 + 5).setSelected(true);
                adapter.refresh(itemBeanList);
                break;
            case R.id.ll_item7:
                Toast.makeText(this, itemBeanList.get(pageNum * 8 + 6).getIconName(), Toast.LENGTH_SHORT).show();
                initSelected();
                itemBeanList.get(pageNum * 8 + 6).setSelected(true);
                adapter.refresh(itemBeanList);
                break;
            case R.id.ll_item8:
                Toast.makeText(this, itemBeanList.get(pageNum * 8 + 7).getIconName(), Toast.LENGTH_SHORT).show();
                initSelected();
                itemBeanList.get(pageNum * 8 + 7).setSelected(true);
                adapter.refresh(itemBeanList);
                break;
            default:
                break;
        }
    }

    /**
     * 初始化圖標的選擇狀態,全部設置為未選中狀態
     */
    private void initSelected() {
        for (int i = 0; i < itemBeanList.size(); i++) {
            itemBeanList.get(i).setSelected(false);
        }
    }

刷新Adapter時我是重新調用了initView方法,并且傳入了修改后的數據源。下面是在Adapter中刷新的方法:

public void refresh(List<NavigationItemBean> itemBeanList){
        initView(itemBeanList);
        notifyDataSetChanged();
    }

運行一下,點擊,咦,怎么沒有反應呢?PageAdapter這里有一個坑了:notifyDataSetChanged只有在ViewPager的頁數發生變化才會刷新頁面,單是某一個頁面的數據發生變化時是沒用的。但是不用著急,我們可以重寫getItemPosition方法,讓其返回POSITION_NONE,強迫viewpager重繪所有的頁面。

/**
     * 使Adapter能夠刷新布局
     */
    private int mChildCount = 0;
    @Override
    public void notifyDataSetChanged() {
        mChildCount = getCount();
        super.notifyDataSetChanged();
    }
    @Override
    public int getItemPosition(Object object) {
        if (mChildCount > 0) {
            mChildCount--;
            return POSITION_NONE;
        }
        return super.getItemPosition(object);
    }

運行一下,點擊,發現可以完美實現我們要的效果了。

4.6 雙擊取消選中

實現雙擊取消選中的效果并不難,我們只需在點擊每一個圖標之前都判斷一下當前的選擇狀態,如果當前為選中的狀態,則將狀態改為未選中,反之,則改為選中。示例代碼如下:

if (itemBeanList.get(pageNum * 8 + 0).isSelected()) {
                    initSelected();
                    itemBeanList.get(pageNum * 8 + 0).setSelected(false);
                } else {
                    initSelected();
                    itemBeanList.get(pageNum * 8 + 0).setSelected(true);
                }

我在代碼中只設置了前面兩項,大家如果想實現所有圖標的雙擊選中事件的話就自己動一下手吧!

5、總結

這個功能我前前后后花了不少時間,在參考別人代碼的基礎上總算是實現了,水平有限,如果博客中有錯漏的地方,歡迎批評指正。我的寫法還是太過簡單粗暴,不夠精巧,而且對資源的占用也比較大,如果你有更好的方法,歡迎交流學習。聽說ViewPager+GridVie也可以實現同樣的效果,接下來我再研究一下,看能不能再寫一篇博客吧!

最后是源碼下載地址:

GitHub

 

來自:http://blog.csdn.net/Lindroid20/article/details/66968410

 

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