今天給大家介紹在android中實作頂部導航菜單左右滑動效果的二種解決方案。
第一種解決方案:
那麼今天第一個示例我仍然使android-support-v4.jar來實作菜單左右滑動效果,關于這個包的資訊,不再詳述,大家可以檢視官方文檔。
實作原理是使用android-support-v4.jar包中viewpager控件,在viewpager控件中設定流布局,再在流布局中設定幾項textview,給每一個textview設定相關參數,事件等。關于viewpager控件可以設定全螢幕滑動效果,當然也可以實作局部滑動效果,下面介紹導航菜單。
關于導航菜單,相信大家對它并不陌生,比如在新聞用戶端中就經常使用左右滑動菜單來顯示不同類别的新聞。網上也有關于這方面的一些示例,但是許多都是使用tabhost來做的,實作了圖檔平滑動畫效果,但沒有實作菜單左右滑動的效果。我們先來看下本示例的效果圖:
以上是效果圖,以下讓我們來看來如何才能實作,先建立程式結構,結構圖如下:
在程式中,我們需要導入android-support-v4.jar包。在slidemenuutil類中設定導航菜單項标簽,如下:
package com.slide.util;
/**
* 滑動菜單選項類
* @description: 滑動菜單選項類
* @filename: slidemenuutil.java
* @package com.slide.util
* @author hanyonglu
* @date 2012-4-20 下午04:51:24
* @version v1.0
*/
public class slidemenuutil {
// 菜單選項
public static string item_mobile = "移動";
public static string item_web = "web";
public static string item_cloud = "雲計算";
public static string item_database = "資料庫";
public static string item_embed = "嵌入式";
public static string item_server = "伺服器";
public static string item_dotnet = ".net";
public static string item_java = "java";
public static string item_safe = "安全";
public static string item_domain = "業界";
public static string item_reseasrch = "研發";
public static string item_manage = "管理";
// 菜單項計數器
public int count = 0;
}
為了實作導航菜單上的左右圖檔,需要在main.xml布局檔案中設定相對布局。
我這個示例中,是把左右導航的圖檔顯示在文字上方,在點選上圖中右三角圖檔時會顯示下一個頁面導航,具體大家可以看下面代碼。
main.xml中設定左右圖檔的相對布局代碼:
<relativelayout
android:id="@+id/linearlayout01"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<android.support.v4.view.viewpager
android:id="@+id/slidemenu"
android:layout_width="fill_parent"
android:layout_height="35dp"
android:background="@drawable/top_bg" />
<relativelayout
android:id="@+id/linearlayout01"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<imageview
android:id="@+id/ivpreviousbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignparentleft="true"
android:layout_alignparenttop="true"
android:paddingtop="10dp"
android:paddingleft="5dp"
android:visibility="invisible"
android:src="@drawable/previous_button" />
</relativelayout>
android:id="@+id/ivnextbutton"
android:layout_alignparentright="true"
android:paddingright="5dp"
android:src="@drawable/next_button" />
<!--
android:id="@+id/ivmenubackgroundcopy"
android:paddingtop="2dp"
android:src="@drawable/menu_bg" />
-->
<imageview
android:id="@+id/ivmenubackground"
android:layout_width="wrap_content"
android:layout_centervertical="true"
android:layout_marginleft="2dp"
android:layout_torightof="@+id/ivpreviousbutton"
android:paddingtop="2dp"
android:visibility="gone"
android:src="@drawable/menu_bg" />
</relativelayout>
代碼中id為ivmenubackground的圖檔是為了在點選一項菜單後設定其背景圖檔,菜單中預設選中第一項“移動”。
在程式結構圖中的item_xxx.xml是為了在選一項菜單後顯示下面的布局内容。這隻是個示例,有興趣的朋友可以改造成其它的布局内容。
我使用二維數組存儲導航菜單項:
private string[][] menus = {{slidemenuutil.item_mobile,slidemenuutil.item_web,
slidemenuutil.item_cloud,slidemenuutil.item_database},
{slidemenuutil.item_embed,slidemenuutil.item_server,
slidemenuutil.item_dotnet,slidemenuutil.item_java},
{slidemenuutil.item_safe,slidemenuutil.item_domain,
slidemenuutil.item_reseasrch,slidemenuutil.item_manage}};
上例代碼中:數組的第一維是用來顯示幾頁資料,第二維是用來顯示每一頁中的幾個菜單項。
在剛開始時,需要初始化導航菜單内容:
layoutinflater inflater = getlayoutinflater();
menuviews = new arraylist<view>();
slidemenulayout menu = new slidemenulayout(this);
for(int i = 0;i < menus.length;i++){
menuviews.add(menu.getslidemenulinerlayout(menus[i],screenwidth));
}
main = (viewgroup)inflater.inflate(r.layout.main, null);
其中,menuviews是用來裝載頁面布局控件,有3個頁面menuviews就有3項。screenwidth是代表螢幕寬度。這裡還使用到slidemenulayout類的執行個體方法:getslidemenulinerlayout(string[] menutextviews,int layoutwidth)
menutextviews是代表每頁中有幾項菜單,layoutwidth是螢幕寬度。該方法中代碼如下:
/**
* 頂部滑動菜單布局
* @param menutextviews
* @param layoutwidth
*/
public view getslidemenulinerlayout(string[] menutextviews,int layoutwidth){
// 包含textview的linearlayout
linearlayout menulinerlayout = new linearlayout(activity);
menulinerlayout.setorientation(linearlayout.horizontal);
// 參數設定
linearlayout.layoutparams menulinerlayoutparames = new linearlayout.layoutparams(
linearlayout.layoutparams.wrap_content,
linearlayout.layoutparams.wrap_content,
1);
menulinerlayoutparames.gravity = gravity.center_horizontal;
// 添加textview控件
for(int i = 0;i < menutextviews.length; i++){
textview tvmenu = new textview(activity);
// 設定辨別值
tvmenu.settag(menutextviews[i]);
tvmenu.setlayoutparams(new layoutparams(layoutwidth / 4,30));
tvmenu.setpadding(30, 14, 30, 10);
tvmenu.settext(menutextviews[i]);
tvmenu.settextcolor(color.white);
tvmenu.setgravity(gravity.center_horizontal);
tvmenu.setonclicklistener(slidemenuonclicklistener);
// 菜單項計數
menuutil.count ++;
// 設定第一個菜單項背景
if(menuutil.count == 1){
tvmenu.setbackgroundresource(r.drawable.menu_bg);
}
menulinerlayout.addview(tvmenu,menulinerlayoutparames);
menulist.add(tvmenu);
return menulinerlayout;
}
上例代碼隻是初始化菜單效果,我是使用textview做為每一項菜單,當然還要給每一項菜單設定事件,事件代碼如下:
// 單個菜單事件
onclicklistener slidemenuonclicklistener = new onclicklistener() {
@override
public void onclick(view v) {
// todo auto-generated method stub
string menutag = v.gettag().tostring();
if(v.isclickable()){
textview = (textview)v;
log.i("slidemenu",
"width:" + textview.getwidth() +
"height:" + textview.getheight());
textview.setbackgroundresource(r.drawable.menu_bg);
for(int i = 0;i < menulist.size();i++){
if(!menutag.equals(menulist.get(i).gettext())){
menulist.get(i).setbackgrounddrawable(null);
}
}
// 點選菜單時改變内容
slidemenuonchange(menutag);
};
上面代碼中的for循環是為了清除其它菜單項的背景,slidemenuonchange(menutag)方法是為了顯示下面的内容。該方法中代碼如下:
// 點選時改内容
private void slidemenuonchange(string menutag){
layoutinflater inflater = activity.getlayoutinflater();
viewgroup llc = (viewgroup)activity.findviewbyid(r.id.linearlayoutcontent);
llc.removeallviews();
if(menutag.equals(slidemenuutil.item_mobile)){
llc.addview(inflater.inflate(r.layout.item_mobile, null));
}else if(menutag.equals(slidemenuutil.item_web)){
llc.addview(inflater.inflate(r.layout.item_web, null));
}else if(menutag.equals(slidemenuutil.item_cloud)){
llc.addview(inflater.inflate(r.layout.item_cloud, null));
}else if(menutag.equals(slidemenuutil.item_database)){
llc.addview(inflater.inflate(r.layout.item_database, null));
}else if(menutag.equals(slidemenuutil.item_embed)){
llc.addview(inflater.inflate(r.layout.item_embed, null));
}else if(menutag.equals(slidemenuutil.item_server)){
llc.addview(inflater.inflate(r.layout.item_server, null));
}else if(menutag.equals(slidemenuutil.item_dotnet)){
llc.addview(inflater.inflate(r.layout.item_dotnet, null));
}else if(menutag.equals(slidemenuutil.item_java)){
llc.addview(inflater.inflate(r.layout.item_java, null));
}else if(menutag.equals(slidemenuutil.item_safe)){
llc.addview(inflater.inflate(r.layout.item_safe, null));
}else if(menutag.equals(slidemenuutil.item_domain)){
llc.addview(inflater.inflate(r.layout.item_domain, null));
}else if(menutag.equals(slidemenuutil.item_reseasrch)){
llc.addview(inflater.inflate(r.layout.item_research, null));
}else if(menutag.equals(slidemenuutil.item_manage)){
llc.addview(inflater.inflate(r.layout.item_manage, null));
另外,為了設定左右導航菜單中的圖檔,需要在viewpager控件中的onpageselected監聽事件中更改圖檔狀态:
@override
public void onpageselected(int arg0) {
int pagecount = menuviews.size() - 1;
pagerindex = arg0;
// 顯示右邊導航圖檔
if(arg0 >= 0 && arg0 < pagecount){
imagenext.setvisibility(view.visible);
}else{
imagenext.setvisibility(view.invisible);
// 顯示左邊導航圖檔
if(arg0 > 0 && arg0 <= pagecount){
imageprevious.setvisibility(view.visible);
imageprevious.setvisibility(view.invisible);
}
說明:如果有多個頁面,則直接顯示右邊導航圖檔:
if(menuviews.size() > 1){
imagenext.setvisibility(view.visible);
如果到達最後一頁時,則隐藏右邊導航圖檔;如果目前頁不是第一頁,則直接顯示左邊導航圖檔。
另外,還需要給這兩個導航圖檔設定單擊事件,在點選時直接顯示下一頁菜單或是上一頁菜單:
// 右導航圖檔按鈕事件
class imagenextonclicklistener implements onclicklistener{
pagerindex ++;
viewpager.setcurrentitem(pagerindex);
}
// 左導航圖檔按鈕事件
class imagepreviousonclicklistener implements onclicklistener{
pagerindex --;
到此,第一種解決方案大緻思路和代碼就已經完了,不過我這裡的實作效果是在滑動時直接顯示下一頁菜單,本頁菜單就給隐藏掉了。有的朋友可能注意到,要想實作一點一點向左滑動或是向右滑動,而不是整個頁面的滑動,也就是如果沒有滑到下一頁會反彈到原來的那頁,就不能用這個方法了,那麼就需要用到horizontalscrollview,關于horizontalscrollview實作的滑動菜單使用及示例,請看下面的第二種解決方案。
另外,在本示例中我沒有實作背景圖檔的平滑向右或是向左的動畫效果,有興趣的的朋友可以把這樣的效果加上,網上有一些實作這樣的效果示例。
第二種解決方案:
第二種解決方案我是采用的horizontalscrollview實作的,這種布局可以實作橫向滑動效果,但要注意隻能有一個直接子标簽。這種方案相比第一種方案要簡單得多,隻需要設定好布局就可以了。先看下示例運作效果:
上圖中實作的導航菜單左右滑動效果可以讓菜單逐漸滑動,我這個示例中沒有出現反彈的現象。好了,讓我們看下布局代碼:
<horizontalscrollview
android:layout_width="match_parent"
android:layout_height="35dp"
android:scrollbars="none" >
<linearlayout
android:id="@+id/linearlayoutmenu"
android:background="@drawable/top_bg"
android:gravity="center_vertical" >
</linearlayout>
</horizontalscrollview>
其中的菜單項我仍然是用textview控件,我這裡是使用代碼添加的textview,如下:
private void setslidemenu(){
// 包含textview的linearlayout
linearlayout menulinerlayout = (linearlayout) findviewbyid(r.id.linearlayoutmenu);
textview tvmenu = new textview(this);
tvmenu.setlayoutparams(new layoutparams(30,30));
tvmenu.settext(menus[i]);
怎麼樣,感覺不難吧。如果要在<horizontalscrollview>上方标題或是下方設定内容,我們可以把<horizontalscrollview>嵌套在其它的布局中,相信這個大家都可以做到,不再多說。
另外,還可以使用gallery來實作導航菜單滑動,關于gallery如何實作,本文就不再詳述,有興趣的朋友可以查詢幫助文檔。
完畢。^_^