Android侧滑菜单的实现

Android侧滑菜单

  • 1.侧滑菜单概述
    • 什么是侧滑菜单
    • 实现侧滑菜单的两种主要方式
  • 2.SlidingMenu开源库应用简介
    • 常用属性介绍
    • 设置SlidingMenu属性
    • 支持右侧划出菜单
  • 3.DrawerLayout详细介绍
    • Drawerlayout概述
    • 使用Drawerlayout的要点

1.侧滑菜单概述

什么是侧滑菜单

侧滑菜单是在应用中非常常见的从侧边划出菜单的一个效果
Android侧滑菜单的实现_第1张图片
在本文中,将讲解如何实现侧滑菜单。

实现侧滑菜单的两种主要方式

1.Slidingmenu开源库https://github.com/jfeinstein10/SlidingMenu
2.Drawerlayout

由于Drawerlayout包含在support包内,可直接拿来使用,更为方便,谷歌在v4包中添加了DrawerLayout之后我们通常使用Drawerlayout来实现侧滑菜单效果。本文将着重讲解如何通过Drawerlayout实现侧滑菜单的效果。

2.SlidingMenu开源库应用简介

SlidingMenu开源库
SlidingMenu 是GitHub上的一个开源项目,用来实现SlidingMenu的菜单效果。目前为止,它提供了侧滑菜单的最佳实现:定制灵活、各种阴影和渐变的滑动效果也很不错。SlidingMenu 是一个开源库,而不是一个完整的项目,要把它作为libary引入到你自己的工程里,简单配置一下就可以实现SlidingMenu的效果。

常用属性介绍

menu.setMode(SlidingMenu.LEFT);//设置左滑菜单
menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);//设置滑动的屏幕范围,该设置为全屏区域都可以滑动
menu.setShadowDrawable(R.drawable.shadow);//设置阴影图片
menu.setShadowWidthRes(R.dimen.shadow_width);//设置阴影图片的宽度
menu.setBehindOffsetRes(R.dimen.slidingmenu_offset);//SlidingMenu划出时主页面显示的剩余宽度
menu.setBehindWidth(400);//设置SlidingMenu菜单的宽度
menu.setFadeDegree(0.35f);//SlidingMenu滑动时的渐变程度
menu.attachToActivity(this,
SlidingMenu.SLIDING_CONTENT);//使SlidingMenu附加在Activity上
menu.setMenu(R.layout.menu_layout);//设置menu的布局文件
menu.toggle();//动态判断自动关闭或开启SlidingMenu menu.showMenu();//显示SlidingMenu
menu.showContent();//显示内容

监听slidingmenu打开

menu.setOnOpenListener(onOpenListener);//监听slidingmenu打开

关于关闭menu有两个监听,简单的来说,对于menu close事件,一个是when,一个是after

menu.OnClosedListener(OnClosedListener);//监听slidingmenu关闭时事件
menu.OnClosedListener(OnClosedListener);//监听slidingmenu关闭后事件

左右都可以划出SlidingMenu菜单只需要设置

menu.setMode(SlidingMenu.LEFT_RIGHT);属性,然后设置右侧菜单的布局文件
menu.setSecondaryShadowDrawable(R.drawable.shadowright);//右侧菜单的阴影图片

设置SlidingMenu属性

sm = getSlidingMenu();//如果只显示左侧菜单就是用LEFT,右侧就RIGHT,左右都支持就LEFT_RIGHT
sm.setMode(SlidingMenu.LEFT_RIGHT);//设置菜单滑动模式,菜单是出现在左侧还是右侧,还是左右两侧都有
sm.setShadowDrawable(R.drawable.shadow);//设置阴影的图片资源
sm.setShadowWidthRes(R.dimen.shadow_width);//设置阴影图片的宽度
sm.setBehindWidth(200);//设置菜单的宽
sm.setBehindOffsetRes(R.dimen.slidingmenu_offset);//SlidingMenu划出时主页面显示的剩余宽度
sm.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);//设置滑动的区域

支持右侧划出菜单

SlidingMenu可以同时支持划出左右两侧的菜单,互不冲突,而且动画优美,体验良好。

sm.setSecondaryMenu(R.layout.menu_frame2);//设置右侧菜单
sm.setSecondaryShadowDrawable(R.drawable.shadowright);//设置右侧菜单阴影的图片资源
//右侧SlidingMenu的Fragment
getSupportFragmentManager().beginTransaction().replace(R.id.menu_frame2,
new SampleListFragment()).commit();

slidingMenu = getSlidingMenu(); //设置是左滑还是右滑,还是左右都可以滑
slidingMenu.setMode(SlidingMenu.LEFT_RIGHT); //设置阴影宽度
slidingMenu.setShadowWidth(getWindowManager().getDefaultDisplay().getWidth()
/ 40); //设置左菜单阴影图片 slidingMenu.setShadowDrawable(R.drawable.shadow);
//设置右菜单阴影图片
slidingMenu.setSecondaryShadowDrawable(R.drawable.right_shadow);
//设置菜单占屏幕的比例
slidingMenu.setBehindOffset(getWindowManager().getDefaultDisplay().getWidth()
/ 5); //设置滑动时菜单的是否淡入淡出 slidingMenu.setFadeEnabled(true); //设置淡入淡出的比例
slidingMenu.setFadeDegree(0.4f); //设置滑动时拖拽效果
slidingMenu.setBehindScrollScale(0); //设置要使菜单滑动,触碰屏幕的范围
slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);

3.DrawerLayout详细介绍

Drawerlayout概述

DrawerLayout是Support Library包中实现了侧滑菜单效果的控件。drawerLayout分为侧边菜单和主内容区两部分,侧边菜单可以根据手势展开与隐藏(drawerLayout自身特性),主内容区的内容可以随着菜单的点击而变化(这需要使用者自己实现)。

使用Drawerlayout的要点

1)drawerLayout是一个布局控件

<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
<android.support.v4.widget.DrawerLayout    
	xmlns:android="http://schemas.android.com/apk/res/android"    
	android:id="@+id/drawer_layout"    
	android:layout_width="match_parent"    
	android:layout_height="match_parent">    
	<!-- As the main content view, the view below consumes the entire         space available using match_parent in both dimensions. -->    
	<FrameLayout        
	    android:id="@+id/content_frame"        
	    android:layout_width="match_parent"        			
	    android:layout_height="match_parent" />    
	<!-- android:layout_gravity="start" tells DrawerLayout to treat         this as a sliding drawer on the left side for left-to-right         languages and on the right side for right-to-left languages.         The drawer is given a fixed width in dp and extends the full height of         the container. A solid background is used for contrast         with the content view. -->    
	<ListView    
	    android:id="@+id/left_drawer"
	    android:layout_width="240dp"        
	    android:layout_height="match_parent"        
	    android:layout_gravity="start"        
	    android:choiceMode="singleChoice"        
	    android:divider="@android:color/transparent"        
	    android:dividerHeight="0dp"        
	    android:background="#111"/>
 </android.support.v4.widget.DrawerLayout>

其中:
1.DrawerLayout最好为界面的根布局,官网是这样说的,否则可能会出现触摸事件被屏蔽的问题;
2.主内容区的布局代码要放在侧滑菜单布局的前面, 因为 XML 顺序意味着按 z 序(层叠顺序)排序,并且抽屉式导航栏必须位于内容顶部;
3.侧滑菜单部分的布局(这里是ListView)必须设置layout_gravity属性,他表示侧滑菜单是在左边还是右边,而且如果不设置在打开关闭抽屉的时候会报错,设置了layout_gravity="start/left"的视图才会被认为是侧滑菜单。

2)建议用ActionBarDrawerToggle来监听

mDrawerToggle = new ActionBarDrawerToggle(    
    this,                  /* host Activity */        
    mDrawerLayout,         /* DrawerLayout object */        
    R.drawable.ic_drawer,  /* nav drawer image to replace 'Up' caret */        
    R.string.drawer_open,  /* "open drawer" description for accessibility */        
    R.string.drawer_close  /* "close drawer" description for accessibility */        
    ) {    
    public void onDrawerClosed(View view) {        
    	getActionBar().setTitle(mTitle);        
    	invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()    
    	}    
    	public void onDrawerOpened(View drawerView) {        
    		getActionBar().setTitle(mDrawerTitle);        
    		invalidateOptionsMenu(); // creates call to 
    		onPrepareOptionsMenu()    
    	}
    };
    mDrawerLayout.setDrawerListener(mDrawerToggle);

drawerLayout左侧菜单(或者右侧)的展开与隐藏可以被DrawerLayout.DrawerListener的实现监听到,这样你就可以在菜单展开与隐藏反生的时刻做一些希望做的事情,比如更新actionbar菜单等。如果你的activity有actionbar的话,还是建议用ActionBarDrawerToggle来监听,ActionBarDrawerToggle实现了DrawerListener,所以他能做DrawerListener可以做的任何事情,同时他还能将drawerLayout的展开和隐藏与actionbar的app 图标关联起来,当展开与隐藏的时候图标有一定的平移效果,点击图标的时候还能展开或者隐藏菜单。

3)如何在菜单展开或者隐藏的时候更新activity的menu

在监听的回调方法中我们用invalidateOptionsMenu通知activity重绘menu,然后activity就有机会在onPrepareOptionsMenu方法中更新menu元素的显示与隐藏。

/* Called whenever we call invalidateOptionsMenu() */
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    // If the nav drawer is open, hide action items related to the content view    
    boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);    
    menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);    
    return super.onPrepareOptionsMenu(menu);
}

4)如何让app图标点击的时候能够展开或者隐藏侧边菜单

Activity中使用ActionBarDrawerToggle的onOptionsItemSelected方法。

@Override
public booleanonOptionsItemSelected(MenuItem item) {
	// The action bar home/up actionshould open or close the drawer.
	// ActionBarDrawerToggle will takecare of this.
	if(mDrawerToggle.onOptionsItemSelected(item)) {
	return true;
	}
	……….//处理其他菜单点击事件
	returnsuper.onOptionsItemSelected(item);
}

Drawerlayout完整实例(源于官网demo)
Activity:

/* 
* Copyright 2013 The Android Open Source Project 
*
 * Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. * You may obtain a copy of the License at 
*
*     http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an "AS IS" BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License. 
*/
package com.example.android.navigationdrawerexample;
import java.util.Locale;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.SearchManager;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Toast;
public class MainActivity extends Activity {
    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;    
    private ActionBarDrawerToggle mDrawerToggle;    
    private CharSequence mDrawerTitle;    
    private CharSequence mTitle;    
    private String[] mPlanetTitles;    
    @Override    
    protected void onCreate(Bundle savedInstanceState) {        
    	super.onCreate(savedInstanceState);        
    	setContentView(R.layout.activity_main);        
    	mTitle = mDrawerTitle = getTitle();        
    	mPlanetTitles = getResources().getStringArray(R.array.planets_array);        
    	mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);        
    	mDrawerList = (ListView) findViewById(R.id.left_drawer);        
    	// set a custom shadow that overlays the main content when the drawer opens        
    	mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);        
    	// set up the drawer's list view with items and click listener        
    	mDrawerList.setAdapter(new ArrayAdapter<String>(this,                R.layout.drawer_list_item, mPlanetTitles));        
    	mDrawerList.setOnItemClickListener(new DrawerItemClickListener());        
    	// enable ActionBar app icon to behave as action to toggle nav drawer        
    	getActionBar().setDisplayHomeAsUpEnabled(true);        
    	getActionBar().setHomeButtonEnabled(true);        
    	// ActionBarDrawerToggle ties together the the proper interactions        
    	// between the sliding drawer and the action bar app icon        
    	mDrawerToggle = new ActionBarDrawerToggle(                
    		this,               /* host Activity */                
    		mDrawerLayout,         /* DrawerLayout object */
    		R.drawable.ic_drawer,  /* nav drawer image to replace 'Up' caret */                
    		R.string.drawer_open,  /* "open drawer" description for accessibility */                
    		R.string.drawer_close  /* "close drawer" description for accessibility */                
    		) {            
    		public void onDrawerClosed(View view) {                
    			getActionBar().setTitle(mTitle);                
    			invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()            
    		}            
    		public void onDrawerOpened(View drawerView) {                
    			getActionBar().setTitle(mDrawerTitle);                
    			invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()            
    			}        
    		};        
    		mDrawerLayout.setDrawerListener(mDrawerToggle);        
    		if (savedInstanceState == null) {            
    			selectItem(0);        
    			}    
    		}    
    		@Override    
    		public boolean onCreateOptionsMenu(Menu menu) {        
    			MenuInflater inflater = getMenuInflater();        
    			inflater.inflate(R.menu.main, menu);        
    			return super.onCreateOptionsMenu(menu);    
    		}   
    		/* Called whenever we call invalidateOptionsMenu() */    
    		@Override    
    		public boolean onPrepareOptionsMenu(Menu menu) {        
    		// If the nav drawer is open, hide action items related to the content view        
    		boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);        
    		menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);        
    		return super.onPrepareOptionsMenu(menu);    
    	}    
    	@Override    
    	public boolean onOptionsItemSelected(MenuItem item) {
    	         // The action bar home/up action should open or close the drawer.         
    	         // ActionBarDrawerToggle will take care of this.        
    	         if (mDrawerToggle.onOptionsItemSelected(item)) {            
    	         	return true;        
    	         }        
    	         // Handle action buttons        
    	         switch(item.getItemId()) {        
    	         case R.id.action_websearch:       
    	              // create intent to perform web search for this planet            
    	              Intent intent = new 
    	              Intent(Intent.ACTION_WEB_SEARCH);            
    	              intent.putExtra(SearchManager.QUERY, getActionBar().getTitle());            
    	              // catch event that there's no activity to handle intent            
    	              if (intent.resolveActivity(getPackageManager()) != null) {                
    	              	startActivity(intent);            
    	              } else {         
    	                     Toast.makeText(this, R.string.app_not_available, Toast.LENGTH_LONG).show();      
    	     	      }            
    	     	      return true;        
    	     	 default:            
    	     	 	return super.onOptionsItemSelected(item);
    	     	 }    
    	     }    
    	     /* The click listner for ListView in the navigation drawer */    
    	     private class DrawerItemClickListener implements ListView.OnItemClickListener {        
    	     @Override        
    	     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {      
    	           selectItem(position);        
    	           }    
    	      }    
    	      private void selectItem(int position) {        
    	      	// update the main content by replacing fragments        
    	      	Fragment fragment = new PlanetFragment();        
    	      	Bundle args = new Bundle();        
    	      	args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);        
    	      	fragment.setArguments(args);        
    	      	FragmentManager fragmentManager = getFragmentManager


	        fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();        
	        // update selected item and title, then close the drawer        
	        mDrawerList.setItemChecked(position, true);        
	        setTitle(mPlanetTitles[position]);        
	        mDrawerLayout.closeDrawer(mDrawerList);    
	        }    
	        @Override    
	        public void setTitle(CharSequence title) {    
	            mTitle = title;        
	            getActionBar().setTitle(mTitle);    
	         }    
	         /**     
	         * When using the ActionBarDrawerToggle, you must call it during     
	         * onPostCreate() and onConfigurationChanged()...     */    
	         @Override    
	         protected void onPostCreate(Bundle savedInstanceState) {        
	         	super.onPostCreate(savedInstanceState);        
	         	// Sync the toggle state after onRestoreInstanceState has occurred.        
	         	mDrawerToggle.syncState();    
	         }    
	         @Override    
	         public void onConfigurationChanged(Configuration newConfig) {        
	         	super.onConfigurationChanged(newConfig);        
	         	// Pass any configuration change to the drawer toggls        
	         	mDrawerToggle.onConfigurationChanged(newConfig);    
	         }    
	         	
	         /**     * Fragment that appears in the "content_frame", shows a planet     */    
	         public static class PlanetFragment extends Fragment {        
	         	public static final String ARG_PLANET_NUMBER = "planet_number";        
	         	public PlanetFragment() {            
	         		// Empty constructor required for fragment subclasses        
	         	}        
	         	@Override        
	         	public View onCreateView(LayoutInflater inflater, ViewGroup container,                Bundle savedInstanceState) {            
	         		View rootView = inflater.inflate(R.layout.fragment_planet, container, false);            
	         		int i = getArguments().getInt(ARG_PLANET_NUMBER);            
	         		String planet = getResources().getStringArray(R.array.planets_array)[i];            
	         		int imageId = getResources().getIdentifier(planet.toLowerCase(Locale.getDefault()),                            "drawable", getActivity().getPackageName());            
	         		((ImageView) rootView.findViewById(R.id.image)).setImageResource(imageId);            
	         		getActivity().setTitle(planet);            return rootView;        
	         	}    
	         }
	  }

activity_main.xml

<android.support.v4.widget.DrawerLayout    
	xmlns:android="http://schemas.android.com/apk/res/android"    
	android:id="@+id/drawer_layout"    
	android:layout_width="match_parent"    
	android:layout_height="match_parent">    
	<!-- As the main content view, the view below consumes the entire         space available using match_parent in both dimensions. -->    
	<FrameLayout        
		android:id="@+id/content_frame"        
		android:layout_width="match_parent"        
		android:layout_height="match_parent" />    
	<ListView        
		android:id="@+id/left_drawer"        
		android:layout_width="240dp"        
		android:layout_height="match_parent"        
		android:layout_gravity="start"        	
		android:choiceMode="singleChoice"        
		android:divider="@android:color/transparent"        
		android:dividerHeight="0dp"        
		android:background="#111"/>
				
</android.support.v4.widget.DrawerLayout>

fragment_planet.xml

<ImageView xmlns:android="http://schemas.android.com/apk/res/android"    
	android:id="@+id/image"    
	android:layout_width="match_parent"    
	android:layout_height="match_parent"    
	android:background="#000000"    
	android:gravity="center"    
	android:padding="32dp" />

drawer_list_item.xml

<TextView xmlns:android="http://schemas.android.com/apk/res/android"    
	android:id="@android:id/text1"    
	android:layout_width="match_parent"    
	android:layout_height="wrap_content"    
	android:textAppearance="?android:attr/textAppearanceListItemSmall"    
	android:gravity="center_vertical"    
	android:paddingLeft="16dp"    
	android:paddingRight="16dp"    
	android:textColor="#fff"    
	android:background="?android:attr/activatedBackgroundIndicator"    
	android:minHeight="?android:attr/listPreferredItemHeightSmall"/>

参考:
1.https://www.cnblogs.com/xueqiang911226/p/3564757.html
2.https://developer.android.com/training/implementing-navigation/nav-drawer.html

作者:蒋秋月
原文链接:https://blog.csdn.net/JQY1515/article/details/106727446

你可能感兴趣的:(android)