功能描述
菜单分左右两侧,整体可以滑动,效果如下
功能分析
widthMeasureSpec:期望值
- 组成: 32位的010101010101011010101组成
- 头2位:代表的是模式
- UNSPECIFIED: 不确定,随意
- EXACTLY:精确的
- AT_MOST:最大的
- 后30位:数值
scrollTo:
- 移动的是手机的屏幕
- 标准移动
scrollBy:
- 移动的是手机的屏幕
- 增量移动
Scroller: 用来模拟数据变化
- computeScroll()
代码实现
- 页面布局
- activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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="com.cdw.slidingmenu.MainActivity">
<com.cdw.slidingmenu.SlidingMenu
android:id="@+id/sm"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--左侧菜单-->
<include layout="@layout/left"/>
<!--右侧内容-->
<include layout="@layout/content"/>
</com.cdw.slidingmenu.SlidingMenu>
</RelativeLayout>
- 左菜单(left.xml)
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="200dp"
android:layout_height="match_parent"
android:background="@drawable/menu_bg"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
style="@style/tab_style"
android:drawableLeft="@drawable/tab_news"
android:text="新闻"/>
<TextView
style="@style/tab_style"
android:drawableLeft="@drawable/tab_read"
android:text="订阅"/>
<TextView
style="@style/tab_style"
android:drawableLeft="@drawable/tab_local"
android:text="本地"/>
<TextView
style="@style/tab_style"
android:drawableLeft="@drawable/tab_ties"
android:text="跟帖"/>
<TextView
style="@style/tab_style"
android:drawableLeft="@drawable/tab_pics"
android:text="图片"/>
<TextView
style="@style/tab_style"
android:drawableLeft="@drawable/tab_ugc"
android:text="话题"/>
<TextView
style="@style/tab_style"
android:drawableLeft="@drawable/tab_vote"
android:text="投票"/>
<TextView
style="@style/tab_style"
android:drawableLeft="@drawable/tab_focus"
android:text="聚合读物"/>
</LinearLayout>
</ScrollView>
- 右边主界面(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:onClick="clickBack"
android:src="@drawable/main_back"/>
<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="wrap_content"
android:text="今日头条"
android:textSize="25sp"
android:layout_margin="5dp"
android:textColor="@android:color/white"
android:layout_gravity="center_vertical"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="新闻内容"
android:textSize="25sp"
android:layout_margin="5dp"
android:gravity="center"/>
</LinearLayout>
- drawable目录下tab_bg.xml选择器
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#3333ffff" android:state_pressed="true"/>
<item android:drawable="@android:color/transparent"/>
</selector>
- styles.xml
<style name="tab_style">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">@android:color/white</item>
<item name="android:textSize">24sp</item>
<item name="android:paddingTop">10dp</item>
<item name="android:paddingLeft">20dp</item>
<item name="android:paddingBottom">10dp</item>
<item name="android:gravity">center_vertical</item>
<item name="android:drawablePadding">15dp</item>
<item name="android:clickable">true</item>
<item name="android:onClick">clickTab</item>
<item name="android:background">@drawable/tab_bg</item>
</style>
- SlidingMenu.java
package com.cdw.slidingmenu;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;
/**
* Created by dongwei on 2016/8/2.
*/
public class SlidingMenu extends ViewGroup {
private View mLeftView;
private View mContentView;
private int mLeftWidth;
private float mDownX;
private float mDownY;
private Scroller mScroller;
private boolean isLeftShow = false;
public SlidingMenu(Context context) {
this(context, null);
}
public SlidingMenu(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
}
@Override
protected void onFinishInflate() {
//xml加载完成时
mLeftView = getChildAt(0);
mContentView = getChildAt(1);
LayoutParams params = mLeftView.getLayoutParams();
mLeftWidth = params.width;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//测量孩子
int leftWidthMeasureSpec = MeasureSpec.makeMeasureSpec(mLeftWidth, MeasureSpec.EXACTLY);
mLeftView.measure(leftWidthMeasureSpec, heightMeasureSpec);
mContentView.measure(widthMeasureSpec, heightMeasureSpec);
//设置自己的宽度和高度
int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(measuredWidth, measuredHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int width = mLeftView.getMeasuredWidth();
int height = mLeftView.getMeasuredHeight();
//给左侧布局
int lvLeft = -width;
int lvTop = 0;
int lvRight = 0;
int lvBottom = height;
mLeftView.layout(lvLeft, lvTop, lvRight, lvBottom);
//给右侧布局
int cLeft = 0;
int cTop = 0;
int cRight = mContentView.getMeasuredWidth();
int cBottom = mContentView.getMeasuredHeight();
mContentView.layout(cLeft, cTop, cRight, cBottom);
}
@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();
if (Math.abs(moveX - mDownX) > Math.abs(moveY - mDownY)){
//水平方向移动
return true;
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return super.onInterceptTouchEvent(ev);
}
@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();
int diffX = (int) (mDownX - moveX + 0.5f);
int scrollX = getScrollX() + diffX;
if (scrollX < 0 && scrollX < -mLeftView.getMeasuredWidth()){
scrollTo(-mLeftView.getMeasuredWidth(), 0);
}else if (scrollX > 0){
scrollTo(0, 0);
}else {
scrollBy(diffX, 0);
}
mDownX = moveX;
mDownY = moveY;
break;
case MotionEvent.ACTION_UP:
//判断是打开还是关闭
int width = mLeftView.getMeasuredWidth();
int currentX = getScrollX();
float middle = -width / 2f;
switchMenu(currentX <= middle);
break;
default:
break;
}
return true;
}
private void switchMenu(boolean showLeft) {
isLeftShow = showLeft;
int width = mLeftView.getMeasuredWidth();
int currentX = getScrollX();
if (!showLeft){
//scrollTo(0, 0);
int startX = currentX;
int startY = 0;
int endX = 0;
int endY = 0;
int dx = endX - startX;
int dy = endY - startY;
int duration = Math.abs(dx) * 10;
if (duration >= 600){
duration = 600;
}
//模拟数据变化
mScroller.startScroll(startX, startY, dx, dy, duration);
}else {
//scrollTo(-width, 0);
int startX = currentX;
int startY = 0;
int endX = -width;
int endY = 0;
int dx = endX - startX;
int dy = endY - startY;
int duration = Math.abs(dx) * 10;
if (duration >= 600){
duration = 600;
}
mScroller.startScroll(startX, startY, dx, dy, duration);
}
invalidate();
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()){
//更新位置
scrollTo(mScroller.getCurrX(), 0);
invalidate();
}
}
public void toggle(){
switchMenu(!isLeftShow);
}
}
- mainActivity.java
package com.cdw.slidingmenu;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private SlidingMenu menu;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
menu = (SlidingMenu) findViewById(R.id.sm);
}
public void clickTab(View view){
String text = ((TextView)view).getText().toString();
Toast.makeText(this, "点击了" + text, Toast.LENGTH_SHORT).show();
menu.toggle();
}
public void clickBack(View view){
menu.toggle();
}
}
项目链接:https://github.com/ChenDongWei/Android/tree/ec78b9b3d2d3bb22b51b0784d26dca18960ab01a/slidingmenu