Android仿餓了么首頁導航欄(ViewPager)
1、需求分析
在餓了么首頁中我們能看到這樣的布局(如下圖)。紅框內是一個可以左右滑動的頁面,每一個頁面類似于九宮格,都有可供點擊圖標。對于這樣的布局,我在網上找了很久都沒有找到相關的名稱,所以我這里暫時叫它導航頁吧。
最近公司的項目就要求我實現一個這樣的布局,但是我們的圖標并不是想餓了么這樣是固定的,所以在餓了么的布局上還要加一個效果:在圖標數目無法排滿兩行時,就只顯示一行。比如說,我們每一頁最多可以顯示兩行和四列,當圖標的總數目小于或等于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也可以實現同樣的效果,接下來我再研究一下,看能不能再寫一篇博客吧!
最后是源碼下載地址:
來自:http://blog.csdn.net/Lindroid20/article/details/66968410