QQ5.0侧滑效果实现方案有很多方式,今天先来介绍一种简单的方式
先上效果图:
①我们先来分析一下,如果想要滑动效果,哪些控件具有滑动效果呢?于是我们想到了ScrollView, HorizontalScrollView, ListView… 通过对比,我们可以找出HorizontalScrollView最符合我们的效果。使用HorizontalScrollView,在适当的时候隐藏部分HorizontalScrollView的内容即可。因此我的自定义View继承HorizontalScrollView就可以了。
/** SlidingMenu就是我们自定义的View控件 */
public class SlidingMenu extends HorizontalScrollView {
private ViewGroup mWapper;// SlidingMenu中的LinearLayout
private ViewGroup mMenu;// 菜单
private ViewGroup mContent;// 主页面内容
private boolean isFirstMeasure = true;// 是否首次测量
private int mMenuRightPadding = 150;// 菜单右边预留宽度
private int mScreentWidth;// 屏幕宽度
private int mMenuWidth;// 菜单宽度
private boolean isOpen = false;// 是否打开菜单
/** 需要重写构造方法 */
public SlidingMenu(Context context) {
this(context, null);
}
public SlidingMenu(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 获取自定义的属性
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlidingMenu, defStyleAttr, 0);
int count = a.getIndexCount();
for (int i = 0; i < count; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.SlidingMenu_rightPadding:
mMenuRightPadding = a.getDimensionPixelSize(attr, dp2px(context, mMenuRightPadding)); // 获取到自定义属性rightPadding的值,即菜单预留宽度
break;
}
}
a.recycle();// 需要及时销毁
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);// 得到窗口管理器
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
mScreentWidth = outMetrics.widthPixels;// 获取屏幕的宽度
}
/** dp转px */
public int dp2px(Context context, int i) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, i, context.getResources().getDisplayMetrics());
}
使用自定义控件,自定义属性。在values/attr.xml中定义
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="rightPadding" format="dimension"/>
<declare-styleable name="SlidingMenu">
<attr name="rightPadding"/>
</declare-styleable>
</resources>
②接着定义下我们主页面的布局文件,使用我们自定义的SlidingMenu控件。布局文件中,我们自定义SlidingMenu中用了LinearLayout, LinearLayout中包含了一个左边布局和主页面的布局。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:lingchen="http://schemas.android.com/apk/res-auto"//如果需要给自定义控件添加属性,需要在这里定义下命名空间
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.yitong.myslidingmenu.MainActivity">
<com.yitong.myslidingmenu.view.SlidingMenu
android:id="@+id/main_menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/bg"
android:fadingEdge="none"
android:overScrollMode="never"
lingchen:rightPadding="60dp"//向自定控件传递值
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<include layout="@layout/left_menu"/>
<LinearLayout
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/qq"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click"
android:text="切换菜单"/>
</LinearLayout>
</LinearLayout>
</com.yitong.myslidingmenu.view.SlidingMenu>
</RelativeLayout>
③接着,回到我们的SlidingMenu中,重写onMeasure(测量控件),onLayout(重新布局)
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (isFirstMeasure) {// 防止重复测量
mWapper = (ViewGroup) getChildAt(0);//获取第一个孩子,即主页面布局中SlidingMenu包含的LinearLayout
mMenu = (ViewGroup) mWapper.getChildAt(0);// 左边布局(菜单布局)
mContent = (ViewGroup) mWapper.getChildAt(1);// 主布局
mMenuWidth = mScreentWidth - mMenuRightPadding - mMenuRightPadding;// 菜单布局的宽度 = 屏幕的宽度 - 右边预留的宽度
mMenu.getLayoutParams().width = mMenuWidth;// 设置菜单的宽度
isFirstMeasure = false;
}
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);
// 通过设置偏移量,将menu隐藏
if (changed) {
this.scrollTo(mMenuWidth, 0);
}
}
③此时,我们的自定义SlingMenu,大致已经设计好了,是不是能简单呢。然后我们添加一些效果,当菜单滑出一半多时,让它自定滑出,否则让它关闭。
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:// 手指抬起时
int scrollX = getScrollX();// 获取左边隐藏的宽度
if (scrollX > mMenuWidth / 2) { // 关闭menu
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
} else {
this.smoothScrollTo(0, 0);
isOpen = true;
}
return true;
}
return super.onTouchEvent(ev);
}
④当菜单打开过程中,添加动画效果,重写onScrollChanged方法即可
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
float scale = l * 1.0f / mMenuWidth;// 1-0
/**
* 分析:
*
* 内容区域:
* 缩放1.0->0.6 => 0.6+0.4*scale
*
* 菜单区域:
* 位移
* 缩放0.6->1.0 => 0.6+0.4*(1-scale)
* 透明度0.6->1.0 => 0.3+0.7*(1-scale)
*/
float rightScale = (float) (0.6 + 0.4 * scale);
float leftScale = (float) (0.6 + 0.4 * (1 - scale));
float leftAphla = (float) (0.2 + 0.7 * (1 - scale));
// 设置内容的缩放中心点
ViewHelper.setPivotX(mContent, 0);
ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);
// 设置内容缩放
ViewHelper.setScaleX(mContent, rightScale);
ViewHelper.setScaleY(mContent, rightScale);
// 设置菜单的位移
ViewHelper.setTranslationX(mMenu, mMenuWidth * scale * 0.6f);
ViewHelper.setScaleX(mMenu, leftScale);
ViewHelper.setScaleY(mMenu, leftScale);
ViewHelper.setAlpha(mMenu, leftAphla);
}
⑤我们这个控件提供一个方法,这个方法就像一个开关按钮,可以控制打开/关闭菜单
/**
* 切换菜单
*/
public void toggle() {
if (isOpen) {
closeMenu();
} else {
openMenu();
}
}
/**
* 打开菜单
*/
private void openMenu() {
if (!isOpen) {
this.smoothScrollTo(0, 0);
isOpen = true;
}
}
/**
* 关闭菜单
*/
private void closeMenu() {
if (isOpen) {
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
}
}
最后完善我们的MainActivity
public class MainActivity extends Activity {
private LinearLayout mMainContent;
private int mScreenWidth;// 屏幕的宽度
private int mScreenHeight;// 屏幕的高度
private SlidingMenu slidingMenu;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
getScreenSize();
intiView();
}
private void intiView() {
mMainContent = (LinearLayout)findViewById(R.id.main_content);
ViewGroup.LayoutParams params = mMainContent.getLayoutParams();
// 设置主页面的宽高,防止不同手机屏幕大小不一
params.width = mScreenWidth;
params.height = mScreenHeight;
slidingMenu = (SlidingMenu) findViewById(R.id.main_menu);
}
public void click(View view) {
slidingMenu.toggle();
}
public void getScreenSize() {
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
mScreenHeight = outMetrics.heightPixels;
}
}
===============至此本文档完==================
如果哪里不清楚,可以留言,博主会及时答复。源码下载,博主使用的是as开发的