侧滑菜单的实现
*分析:由于侧滑菜单的孩子可以装各种组件,所以该定义组件必须是一个容器viewGroup
左边侧滑菜单的布局文件left_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="200dp"
android:layout_height="match_parent"
android:background="@drawable/menu_bg"
android:orientation="vertical">
<!-- 新闻选项 -->
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
右边内容区的布局文件 content.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- 标题栏 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/top_bar_bg" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/main_back"
android:onClick="onBack" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/top_bar_divider" />
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="网易新闻"
android:textSize="20sp"
android:textColor="@android:color/white"
android:gravity="center_vertical"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="内容"
android:gravity="center"/>
</LinearLayout>
mainactivity的布局文件activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.andriodbus.slidingmenuview.SlidingMenuView
android:id="@+id/smvg"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<include layout="@layout/content" />
<include layout="@layout/left_menu" />
</com.andriodbus.slidingmenuview.SlidingMenuView>
</RelativeLayout>
自定义控件 slidingMenuView
package com.andriodbus.slidingmenuview;
import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;
/*
* @项目名: SlidingMenuView
* @包名:com.andriodbus.slidingmenuview
* @文件名: SlidingMenuView
* @创建者: Administrator
* @创建时间: 2016/8/19 0019 下午 8:45
* @描述:TODO
*/
public class SlidingMenuView extends ViewGroup {
private View mContentChild;
private View mLeftChild;
private float mDownX;
private float mDownY;
private Scroller mScroller;
public SlidingMenuView(Context context) {
this(context, null);
}
public SlidingMenuView(Context context, AttributeSet attrs) {
super(context, attrs);
//创建scroller对象,以便能平滑滚回
mScroller = new Scroller(context);
}
//测量
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//测量孩子的宽高,并封装成规格
//这里由于两个孩子都是linealayout,都有自己向父亲申请的宽高,便于操作这里使用measureChildren统一进行了测量
measureChildren(widthMeasureSpec, heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//布局孩子,首先获得这两个孩子
mContentChild = getChildAt(0);
mLeftChild = getChildAt(1);
//进行布局
mContentChild.layout(0,
0,
mContentChild.getMeasuredWidth(),
mContentChild.getMeasuredHeight());
mLeftChild.layout(-mLeftChild.getMeasuredWidth(), 0, 0, mLeftChild.getMeasuredHeight());
}
/**
* 为防止slidingmenuview这个控件在左右滑动时,其父控件随之移动,需要左右滑动拦截,上下交给子类处理
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = ev.getX();
mDownY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
float moveX = ev.getX();
float moveY = ev.getY();
float dx = Math.abs(moveX - mDownX);
float dy = Math.abs(moveY - mDownY);
//进行左右滑动的判断拦截
if (dx > dy) {
return true;
}
break;
}
return super.onInterceptTouchEvent(ev);
}
/**
* 进行侧滑菜单的操作
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = event.getX();
mDownY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
float moveX = event.getX();
float moveY = event.getY();
//计算滑动的偏移
float GapX = mDownX - moveX;
//计算最终的偏移量
float finalX = getScrollX() + GapX;
//判断滑动的合理范围
if (finalX > 0) {
//右边内容区左侧不能滑出(0,0)点
scrollTo(0,0);
//滑动到边界范围时,进制滑动
return true;
} else if (finalX < -mLeftChild.getMeasuredWidth()) {
//拉出左边侧滑菜单时,左侧不能超过(0,0)点
scrollTo(-mLeftChild.getMeasuredWidth(),0);
return true;
}
//滑动菜单
scrollBy((int) GapX, 0);
//更新滑动的起始位置
mDownX = moveX;
break;
case MotionEvent.ACTION_UP:
float upX = event.getX();
//释放时,要么关闭侧滑菜单要么打开,需要进行判断
if (getScrollX() < -mLeftChild.getWidth() / 2) {
//侧滑菜单拉出一半以上时,打开
open();
} else {
close();
}
break;
}
return true; //这里必须返回true,表示自己消费了事件
}
private boolean isOpen = false;
private void open() {
smoothTo(-mLeftChild.getWidth());
isOpen = true;
}
private void close() {
smoothTo(0);
isOpen = false;
}
private void smoothTo(int endX) {
//调用scroller对象的开始滚动方法
int startX = getScrollX();
int startY = 0;
int dx = endX - startX;
int dy = 0;
int duration = 500;
mScroller.startScroll(startX, startY, dx, dy, duration);
//回滚时触发重新绘制
invalidate();
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
//当重新绘制完成时,停止重绘,滚动到当前位置
scrollTo(mScroller.getCurrX(),0);
//这里可以做兼容性操作的触发重绘
ViewCompat.postInvalidateOnAnimation(this);
}
super.computeScroll();
}
/**
* 对外提供控制侧滑菜单开关的方法
*/
public void setToggle() {
if (isOpen) {
//关闭
close();
} else {
//打开
open();
}
}
}
最后是在 MainActivity中使用SlidingMenuView
package com.andriodbus.slidingmenuview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private SlidingMenuView mSlidingMenuView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSlidingMenuView = (SlidingMenuView) findViewById(R.id.smvg);
}
public void onBack(View view) {
//点击菜单按钮,控制侧滑菜单开关
mSlidingMenuView.setToggle();
}
}