在网上学习了自定义slidingmenu组件,这里记录下其中的关键点。
SlidingMenu其实是一个HorizontalScrollView,里面有两个布局,通过重写几个方法达到侧滑的效果。
首先原理是在LinearLayout外嵌套了HorizontalScrollView,SlidingMenu继承HorizontalScrollView。
重写onMeasure(int widthMeasureSpec, int heightMeasureSpec),onLayout(boolean changed, int l, int t, int r, int b),onTouchEvent(MotionEvent ev)方法
下面是代码
package com.example.slidingmenudemo.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import com.example.slidingmenudemo.R;
import com.example.slidingmenudemo.utils.ScreenUtils;
import com.nineoldandroids.view.ViewHelper;
public class SlidingMenu extends HorizontalScrollView {
// 屏幕的宽度
private int mScreenWidth;
// 菜单的宽度
private int mMenuWidth;
// 一半菜单的宽度
private int mHalfMenuWidth;
// 菜单距离右侧的宽度(像素)
private int mMenuRightPadding;
// 菜单距离右侧的宽度(dp)
private float mDefaultMenuRightPaddingDp = 150f;
// 是否第一次加载
private boolean firstIn = true;
private boolean isOpen = false;
private ViewGroup menu;
private ViewGroup content;
public SlidingMenu(Context context, AttributeSet attrs) {
super(context, attrs);
mScreenWidth = ScreenUtils.getScreenWidth(context);
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.SlidingMenu);
int n = typedArray.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = typedArray.getIndex(i);
switch (attr) {
case R.styleable.SlidingMenu_rightPadding:
mMenuRightPadding = typedArray.getDimensionPixelOffset(attr,
ScreenUtils.dp2px(context, mDefaultMenuRightPaddingDp));
break;
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 如果是第一次加载,要对每个布局(Menu,Content)的宽度重新设定(注意都是像素为单位)
if (firstIn) {
LinearLayout wrapper = (LinearLayout) getChildAt(0);
menu = (ViewGroup) wrapper.getChildAt(0);
content = (ViewGroup) wrapper.getChildAt(1);
mMenuWidth = mScreenWidth - mMenuRightPadding;
mHalfMenuWidth = mMenuWidth / 2;
menu.getLayoutParams().width = mMenuWidth;
content.getLayoutParams().width = mScreenWidth;
}
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 (changed) {
// 将菜单隐藏
this.scrollTo(mMenuWidth, 0);
firstIn = false;
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
ev.getAction();
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:
if (getScrollX() > mHalfMenuWidth) {
// 打开菜单
this.smoothScrollTo(mMenuWidth, 0);
isOpen = true;
} else {
// 关闭菜单
this.smoothScrollTo(0, 0);
isOpen = false;
}
return true;
}
return super.onTouchEvent(ev);
}
// 打开Menu
public void openMenu() {
if (!isOpen) {
this.smoothScrollTo(0, 0);
isOpen = true;
}
}
// 打开Menu
public void closeMenu() {
if (isOpen) {
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
}
}
// 切换菜单状态
public void toggle() {
if (isOpen) {
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
} else {
this.smoothScrollTo(0, 0);
isOpen = true;
}
}
}
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SlidingMenu">
<attr name="rightPadding" format="dimension"></attr>
</declare-styleable>
</resources>
布局main.xml
<com.example.slidingmenudemo.widget.SlidingMenu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:menu="http://schemas.android.com/apk/res/com.example.slidingmenudemo"
android:id="@+id/menu"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:scrollbars="none"
menu:rightPadding="150dp" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<include layout="@layout/layout_menu" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/qq" >
</LinearLayout>
</LinearLayout>
</com.example.slidingmenudemo.widget.SlidingMenu>
要注意的几点:
1.代码的操作都是用的px,所以要把dp转成像素进行计算,这里谢了
2.HorizontalScrollView的smoothScrollTo(mMenuWidth, 0)方法跳到开始content布局中
3.重写onMeasure()中对menu和content布局的宽度都进行了重新的设定,这里menu距离右侧距离是一个自定义属性
创建自定义组件的步骤:
一.写布局
二写java类,一般名字就是自定义组件的名字,在这里写对布局中一些东西操作
三.如果需要自定义属性,先在attr.xml中声明一个类似这种的属性参数,写清楚每个属性的名字和类型
<declare-styleable name="SlidingMenu">
<attr name="rightPadding" format="dimension"></attr>
</declare-styleable>
四.在自定义组件中获取布局文件中写的自定义属性
<pre name="code" class="java"> TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.SlidingMenu);
int n = typedArray.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = typedArray.getIndex(i);
switch (attr) {
case R.styleable.SlidingMenu_rightPadding:
mMenuRightPadding = typedArray.getDimensionPixelOffset(attr,
ScreenUtils.dp2px(context, mDefaultMenuRightPaddingDp));
break;
}
}
这个代码很固定,记住吧,或者慢慢来。
四.布局中记得加上自定义属性的命名空间
xmlns:menu="http://schemas.android.com/apk/res/com.example.slidingmenudemo"
源代码基本上都在上面了,有过有需要项目代码的,请留下邮箱,我看到后会发过去。