在网上学习了自定义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>
<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"
原文:http://blog.csdn.net/u013173289/article/details/42397649