今天给大家介绍在Android中实现顶部导航菜单左右滑动效果的二种解决方案。

  第一种解决方案:

  在以前的一篇博文中我使用android-support-v4.jar实现了左右滑动指引效果,有兴趣的朋友可以查看http://www.cnblogs.com/hanyonglu/archive/2012/04/07/2435589.html

  那么今天第一个示例我仍然使android-support-v4.jar来实现菜单左右滑动效果,关于这个包的信息,不再详述,大家可以查看官方文档。

  实现原理是使用android-support-v4.jar包中ViewPager控件,在ViewPager控件中设置流布局,再在流布局中设置几项TextView,给每一个TextView设置相关参数,事件等。关于ViewPager控件可以设置全屏幕滑动效果,当然也可以实现局部滑动效果,下面介绍导航菜单。

  关于导航菜单,相信大家对它并不陌生,比如在新闻客户端中就经常使用左右滑动菜单来显示不同类别的新闻。网上也有关于这方面的一些示例,但是许多都是使用Tabhost来做的,实现了图片平滑动画效果,但没有实现菜单左右滑动的效果。我们先来看下本示例的效果图:

  以上是效果图,以下让我们来看来如何才能实现,先建立程序结构,结构图如下:

  在程序中,我们需要导入android-support-v4.jar包。在SlideMenuUtil类中设置导航菜单项标签,如下:

packagecom.slide.util;

/**
*滑动菜单选项类
*@Description:滑动菜单选项类

*@FileName:SlideMenuUtil.java

*@Packagecom.slide.util

*@AuthorHanyonglu

*@Date2012-4-20下午04:51:24

*@VersionV1.0
*/
public classSlideMenuUtil{
// 菜单选项
public staticStringITEM_MOBILE="移动";
public staticStringITEM_WEB="Web";
public staticStringITEM_CLOUD="云计算";
public staticStringITEM_DATABASE="数据库";
public staticStringITEM_EMBED="嵌入式";
public staticStringITEM_SERVER="服务器";
public staticStringITEM_DOTNET=".NET";
public staticStringITEM_JAVA="JAVA";
public staticStringITEM_SAFE="安全";
public staticStringITEM_DOMAIN="业界";
public staticStringITEM_RESEASRCH="研发";
public staticStringITEM_MANAGE="管理";
// 菜单项计数器
public intcount=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 >

< RelativeLayout
android:id ="@+id/linearLayout01"
android:layout_width
="match_parent"
android:layout_height
="wrap_content"
android:orientation
="horizontal" >

< ImageView
android:id ="@+id/ivNextButton"
android:layout_width
="wrap_content"
android:layout_height
="wrap_content"
android:layout_alignParentRight
="true"
android:layout_alignParentTop
="true"
android:paddingTop
="10dp"
android:paddingRight
="5dp"
android:visibility
="invisible"
android:src
="@drawable/next_button" />

<!--
<ImageView
android:id="@+id/ivMenuBackgroundCopy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:paddingTop="2dp"
android:src="@drawable/menu_bg"/>
-->

</ RelativeLayout >

< ImageView
android:id ="@+id/ivMenuBackground"
android:layout_width
="wrap_content"
android:layout_height
="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是为了在选一项菜单后显示下面的布局内容。这只是个示例,有兴趣的朋友可以改造成其它的布局内容。

  我使用二维数组存储导航菜单项:

privateString[][]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}};

  

  上例代码中:数组的第一维是用来显示几页数据,第二维是用来显示每一页中的几个菜单项。

  在刚开始时,需要初始化导航菜单内容:

LayoutInflaterinflater=getLayoutInflater();
menuViews= newArrayList<View>();
SlideMenuLayoutmenu= newSlideMenuLayout( this);

for( inti=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
*/
publicViewgetSlideMenuLinerLayout(String[]menuTextViews, intlayoutWidth){
// 包含TextView的LinearLayout
LinearLayoutmenuLinerLayout= newLinearLayout(activity);
menuLinerLayout.setOrientation(LinearLayout.HORIZONTAL);

// 参数设置
LinearLayout.LayoutParamsmenuLinerLayoutParames= newLinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT,
1);
menuLinerLayoutParames.gravity=Gravity.CENTER_HORIZONTAL;

// 添加TextView控件
for( inti=0;i<menuTextViews.length;i++){
TextViewtvMenu= newTextView(activity);
// 设置标识值
tvMenu.setTag(menuTextViews[i]);
tvMenu.setLayoutParams( newLayoutParams(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);
}

returnmenuLinerLayout;
}

  上例代码只是初始化菜单效果,我是使用TextView做为每一项菜单,当然还要给每一项菜单设置事件,事件代码如下:

// 单个菜单事件
OnClickListenerSlideMenuOnClickListener= newOnClickListener(){

@Override
public voidonClick(Viewv){
// TODOAuto-generatedmethodstub
StringmenuTag=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( inti=0;i<menuList.size();i++){
if(!menuTag.equals(menuList.get(i).getText())){
menuList.get(i).setBackgroundDrawable( null);
}
}

// 点击菜单时改变内容
slideMenuOnChange(menuTag);
}
}
};

  上面代码中的for循环是为了清除其它菜单项的背景,slideMenuOnChange(menuTag)方法是为了显示下面的内容。该方法中代码如下:

// 点击时改内容
private voidslideMenuOnChange(StringmenuTag){
LayoutInflaterinflater=activity.getLayoutInflater();
ViewGroupllc=(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 voidonPageSelected( intarg0){
intpageCount=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);
} else{
imagePrevious.setVisibility(View.INVISIBLE);
}
}

  说明:如果有多个页面,则直接显示右边导航图片:

if(menuViews.size()>1){
imageNext.setVisibility(View.VISIBLE);
}

  如果到达最后一页时,则隐藏右边导航图片;如果当前页不是第一页,则直接显示左边导航图片。

  另外,还需要给这两个导航图片设置单击事件,在点击时直接显示下一页菜单或是上一页菜单:

// 右导航图片按钮事件
classImageNextOnclickListener implementsOnClickListener{
@Override
public voidonClick(Viewv){
// TODOAuto-generatedmethodstub
pagerIndex++;
viewPager.setCurrentItem(pagerIndex);
}
}

// 左导航图片按钮事件
classImagePreviousOnclickListener implementsOnClickListener{
@Override
public voidonClick(Viewv){
// TODOAuto-generatedmethodstub
pagerIndex--;
viewPager.setCurrentItem(pagerIndex);
}
}

  到此,第一种解决方案大致思路和代码就已经完了,不过我这里的实现效果是在滑动时直接显示下一页菜单,本页菜单就给隐藏掉了。有的朋友可能注意到,要想实现一点一点向左滑动或是向右滑动,而不是整个页面的滑动,也就是如果没有滑到下一页会反弹到原来的那页,就不能用这个方法了,那么就需要用到HorizontalScrollView,关于HorizontalScrollView实现的滑动菜单使用及示例,请看下面的第二种解决方案。

  另外,在本示例中我没有实现背景图片的平滑向右或是向左的动画效果,有兴趣的的朋友可以把这样的效果加上,网上有一些实现这样的效果示例。

  第二种解决方案:

  第二种解决方案我是采用的HorizontalScrollView实现的,这种布局可以实现横向滑动效果,但要注意只能有一个直接子标签。这种方案相比第一种方案要简单得多,只需要设置好布局就可以了。先看下示例运行效果:

  上图中实现的导航菜单左右滑动效果可以让菜单逐步滑动,我这个示例中没有出现反弹的现象。好了,让我们看下布局代码:

<HorizontalScrollView
android:layout_width= " match_parent "
android:layout_height= " 35dp "
android:scrollbars= " none ">

<LinearLayout
android:id= " @+id/linearLayoutMenu "
android:layout_width= " match_parent "
android:layout_height= " wrap_content "
android:background= " @drawable/top_bg "
android:gravity= " center_vertical ">

</LinearLayout>
</HorizontalScrollView>

  其中的菜单项我仍然是用TextView控件,我这里是使用代码添加的TextView,如下:

private voidsetSlideMenu(){
// 包含TextView的LinearLayout
LinearLayoutmenuLinerLayout=(LinearLayout)findViewById(R.id.linearLayoutMenu);
menuLinerLayout.setOrientation(LinearLayout.HORIZONTAL);
// 参数设置
LinearLayout.LayoutParamsmenuLinerLayoutParames= newLinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT,
1);
menuLinerLayoutParames.gravity=Gravity.CENTER_HORIZONTAL;

// 添加TextView控件
for( inti=0;i<menus.length;i++){
TextViewtvMenu= newTextView( this);
tvMenu.setLayoutParams( newLayoutParams(30,30));
tvMenu.setPadding(30,14,30,10);
tvMenu.setText(menus[i]);
tvMenu.setTextColor(Color.WHITE);
tvMenu.setGravity(Gravity.CENTER_HORIZONTAL);
menuLinerLayout.addView(tvMenu,menuLinerLayoutParames);
}
}

  怎么样,感觉不难吧。如果要在<HorizontalScrollView>上方标题或是下方设置内容,我们可以把<HorizontalScrollView>嵌套在其它的布局中,相信这个大家都可以做到,不再多说。

  另外,还可以使用Gallery来实现导航菜单滑动,关于Gallery如何实现,本文就不再详述,有兴趣的朋友可以查询帮助文档。

  最后,希望转载的朋友能够尊重作者的劳动成果,加上转载地址:http://www.cnblogs.com/hanyonglu/archive/2012/04/21/2462311.html,谢谢。


  示例1代码下载:/Files/hanyonglu/AndroidFile/MySlideMenu.rar


  示例2代码下载:/Files/hanyonglu/AndroidFile/MyScrollViewMenu.rar

  完毕。^_^

更多相关文章

  1. Android(安卓)Gallery 滑动停止监听方案
  2. 安卓ScrollView嵌套RecyclerView,GridView,ViewPager冲突解决
  3. Android(安卓)Launcher源码研究(一) 基本结构
  4. android之onCreateOptionsMenu失效,按菜单键无反应
  5. 菜单项选项
  6. Android(安卓)ViewPager 实现多个页面切换滑动
  7. Android(安卓)NestedScrolling嵌套滑动机制
  8. Android项目开发技术总结
  9. Android(安卓)Jetpack 最佳开发姿势

随机推荐

  1. 为什么说Android令人沮丧!?
  2. Android状态check、focused、pressed、se
  3. Android安装以及Eclipse插件(Google Andr
  4. Ubuntu 试用Android(安卓)L版本
  5. android 10 高通 图标名称双行显示
  6. Android收藏商品/关注商品
  7. android开源新闻小程序、3D翻转公告效果
  8. 记-Android(安卓)studio使用的小疑惑
  9. vs2015 支持Android(安卓)arm neon Intro
  10. android之【ArrayAdapter】