侧滑菜单实质上是一个含有两个子item的ViewGroup,第一个item是menu,第二个item是content。
简易demo的实现代码:
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"
tools:context=".MainActivity" >
<com.itheima.slideone.MySlideView
android:id="@+id/msv"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<include layout="@layout/main_menu"/>
<include layout="@layout/main_content"/>
</com.itheima.slideone.MySlideView>
</RelativeLayout>
main_menu.xml
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="200dp"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="200dp"
android:layout_height="wrap_content"
android:background="@drawable/menu_bg"
android:orientation="vertical" >
<TextView
style="@style/menu_style"
android:drawableLeft="@drawable/tab_focus"
android:text="焦点" />
<TextView
style="@style/menu_style"
android:drawableLeft="@drawable/tab_local"
android:text="本地" />
<TextView
style="@style/menu_style"
android:drawableLeft="@drawable/tab_news"
android:text="新闻" />
<TextView
style="@style/menu_style"
android:drawableLeft="@drawable/tab_pics"
android:text="图片" />
<TextView
style="@style/menu_style"
android:drawableLeft="@drawable/tab_read"
android:text="读书" />
<TextView
style="@style/menu_style"
android:drawableLeft="@drawable/tab_ties"
android:text="热贴" />
<TextView
style="@style/menu_style"
android:drawableLeft="@drawable/tab_ugc"
android:text="点评" />
<TextView
style="@style/menu_style"
android:drawableLeft="@drawable/tab_vote"
android:text="投票" />
</LinearLayout>
</ScrollView>
main_contant.xml
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity" >
<LinearLayout
android:background="@drawable/top_bar_bg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<ImageView
android:id="@+id/main_back"
android:background="@drawable/main_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:background="@drawable/top_bar_divider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="新闻"
android:textColor="@android:color/white"
android:textSize="30sp"
android:textStyle="bold" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="寻找马航失联客机"
android:textSize="30sp"
android:textStyle="bold" />
</LinearLayout>
实现构造方法时,注意初始化Scroller。
继承ViewGroup时两个需要重写的方法:
1. 测量尺寸时的回调方法onMeasure()
在onMeasure()中,调用measure()来做
2. 确定位置时的回调方法onLayout()
public class MySlideView extends ViewGroup{
private View content;
private View menu;
private boolean isMenuShow = false;
private Scroller scroller ;
public MySlideView(Context context, AttributeSet attrs) {
super(context, attrs);
scroller = new Scroller(context);
}
/**
* 测量尺寸时的回调方法
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
menu = getChildAt(0);
content = getChildAt(1);
menu.measure(MeasureSpec.makeMeasureSpec(menu.getLayoutParams().width, MeasureSpec.EXACTLY), heightMeasureSpec);
content.measure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 设置页面各位置
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
System.out.println("layout:::"+getChildCount());
menu.layout(0-menu.getMeasuredWidth(), 0, 0, b); //隐藏在页面左边
content.layout(0, 0, r, b); //显示于整个页面
}
private int firstX;
private int lastX;
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
firstX = lastX = (int) event.getX();
break;
case MotionEvent.ACTION_MOVE:
int disX = (int) (lastX - event.getX());
lastX = (int) event.getX();
int nextScrollX = getScrollX()+disX; //getScrollX() 就是当前view的左上角相对于母视图的左上角的X轴偏移量
if( nextScrollX >= -menu.getWidth() && nextScrollX <=0){ //没有滚动到最右边&&没有滚动到最左边
scrollBy(disX, 0); //则移动disX的距离
}
break;
case MotionEvent.ACTION_UP:
int curScrollX = getScrollX(); //当前滚动距离
if(curScrollX > -menu.getWidth()/2){ //如果滚动距离的绝对值不到menu宽度的1/2
isMenuShow = false;
}else{ //如果滚动距离的绝对值超过menu宽度的1/2
isMenuShow = true;
}
flushState(); //刷新页面
break;
}
return true;
}
/**
* 刷新状态
*/
private void flushState() {
int distance = 0;
if(!isMenuShow){
// scrollTo(0,0);
distance = 0-getScrollX();
}else{
// scrollTo(-menu.getWidth(),0);
distance = -menu.getWidth()-getScrollX();
}
scroller.startScroll(getScrollX(), 0, distance, 0);
invalidate();
}
@Override
public void computeScroll() {
if(scroller.computeScrollOffset()){
scrollTo(scroller.getCurrX(),0);
invalidate();
}
}
public void changeState() {
isMenuShow = !isMenuShow;
flushState();
}
}
MainActivity.java
public class MainActivity extends Activity {
private MySlideView msv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
msv = (MySlideView) findViewById(R.id.msv);
findViewById(R.id.main_back).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
msv.changeState();
}
});
}
public void onClick(View v){
TextView tv = (TextView) v;
Toast.makeText(this,tv.getText(), 0).show();
}
}