自定义组件之侧边栏 SlidingMenu
1、侧边栏的功能
A、滑动Activity可以打开侧边栏
B、如果滑动的距离小于临界边距,则自动回滚,否则,惯性打开
C、点击某个按钮可以打开/隐藏侧边栏
2、侧边栏的实现思路
A、侧边栏组件的父类不再使用ViewGroup,而是使用HorizontalScrollView,使用该类的目的是可以简化滚动功能的实现,HorizontalScrollView已经实现了自动滚动的功能
B、结构图
说明:
1)默认情况下,侧边栏隐藏
2)指定侧边栏的宽度,主界面的宽度和屏幕宽度相同
3、HorizontalScrollView的相关方法
A、getScrollX()
获取x方向左部被隐藏的距离,(侧边栏隐藏的长度)
B、smoothScrollTo(int x, int y)
滚动到指定的位置(有动画)
4、需要重写的方法
A、重写onMeasure()方法,指定侧边栏和主界面的宽度,HorizontalScrollView会自动算出总宽度
B、重写onLayout()方法,默认情况下在该方法中隐藏侧边栏
C、重写onTouchEvent()方法,当手指松开的时候,决定侧边栏是显示还是隐藏
5、实现
A、SlidingMenu.java
package com.trkj.dept12_slidingmenu;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
/**
* 侧边栏
* @author huzhiwei
*
*/
public class SlidingMenu extends HorizontalScrollView {
private int leftPaddingWidth; //侧边栏的宽度
private boolean isOpen = false;//侧边栏是否打开
private boolean once = false;//默认只隐藏一次
/**
* 获取屏幕的宽度
* @return
*/
private int getScreenWidth(){
Activity context = (Activity) getContext();
DisplayMetrics dm = new DisplayMetrics();
context.getWindow().getWindowManager()
.getDefaultDisplay().getMetrics(dm);
return dm.widthPixels;
}
/**
* 指定侧边栏和主界面的宽
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
once = true;
//水平滚动View只能有一个直接子组件
LinearLayout subView = (LinearLayout) this.getChildAt(0);
//指定侧边栏和主界面的宽
//第0个子组件就是侧边栏,第1个组件就是主界面
LinearLayout slidingMenu =
(LinearLayout) subView.getChildAt(0);
//第1个子组件是主界面
ViewGroup content = (ViewGroup) subView.getChildAt(1);
//设置侧边的宽度
slidingMenu.getLayoutParams().width = leftPaddingWidth;
//设置主界面的宽度
content.getLayoutParams().width = this.getScreenWidth();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 默认情况下在该方法中隐藏侧边栏
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
//下面的代码只调用一次
if(once){
//隐藏侧边栏
this.scrollTo(leftPaddingWidth, 0);
}
once = false;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
//当手指松开的时候,决定侧边栏是显示还是隐藏
//如果侧边栏滑动显示的宽度大于等于侧边栏的一半,则显示完整的侧边栏
//如果侧边栏滑动显示的宽度小于侧边栏的一半,则隐藏侧边栏
if(ev.getAction() == MotionEvent.ACTION_UP){
int dx = this.getScrollX();//dx为侧边栏隐藏的长度
int halfWidth = this.leftPaddingWidth / 2;
Log.i("SlidingMenu", "dx:" + this.getScrollX() + " halfWidth:" + halfWidth);
if(dx < halfWidth){
//显示侧边栏
this.smoothScrollTo(0, 0);
Log.i("SlidingMenu", "显示");
this.isOpen = true;
}else{
//隐藏侧边栏
this.smoothScrollTo(leftPaddingWidth, 0);
Log.i("SlidingMenu", "隐藏");
this.isOpen = false;
}
return true;
}
return super.onTouchEvent(ev);
}
/**
* 打开
*/
public void open(){
if(!isOpen){
this.smoothScrollTo(0, 0);
isOpen = true;
}
}
/**
* 隐藏
*/
public void hide(){
if(isOpen){
this.smoothScrollTo(leftPaddingWidth, 0);
isOpen = false;
}
}
/**
* 打开隐藏
*/
public void toggle(){
if(isOpen){
hide();
}else{
open();
}
}
public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public SlidingMenu(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.SlidingMenu);
leftPaddingWidth = a.getDimensionPixelSize(
R.styleable.SlidingMenu_left_padding_width,
(int)TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 200,
context.getResources().getDisplayMetrics()));
a.recycle();
}
public SlidingMenu(Context context) {
super(context);
}
}
B、attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SlidingMenu">
<!-- 指定侧边栏的宽度 -->
<attr name="left_padding_width" format="dimension"/>
</declare-styleable>
</resources>
C、activity_main.xml
<com.trkj.dept12_slidingmenu.SlidingMenu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:trkj="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/slidingMenu"
android:scrollbars="none"
trkj:left_padding_width="200dp" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal" >
<!-- 侧边栏 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#FF0000"
android:orientation="vertical" >
</LinearLayout>
<!-- 主界面 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:orientation="vertical" >
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="侧边栏"
android:id="@+id/btn"
android:onClick="toggle"
/>
</LinearLayout>
</LinearLayout>
</com.trkj.dept12_slidingmenu.SlidingMenu>
D、MainActivity.java
package com.trkj.dept12_slidingmenu;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
public class MainActivity extends Activity {
private SlidingMenu slidingMenu;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
slidingMenu = (SlidingMenu) findViewById(R.id.slidingMenu);
}
public void toggle(View v){
slidingMenu.toggle();
}
}
效果图: