Welcome

首页 / 移动开发 / Android / 基于Android实现仿QQ5.0侧滑

本课程将带领大家通过自定义控件实现QQ5.0侧滑菜单,课程将循序渐进,首先实现最普通的侧滑菜单,然后引入属性动画与拖动菜单效果相结合,最终实现QQ5.0侧滑菜单效果。通过本课程大家会对侧滑菜单有更深层次的了解,通过自定义控件和属性动画打造千变万化的侧滑菜单效果
效果图如下所示:


package com.example;import android.os.Bundle;import android.support.v7.app.ActionBarActivity;import android.view.View;public class MainActivity extends ActionBarActivity {private SlidingMenu mMenu;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mMenu = (SlidingMenu) findViewById(R.id.id_menu);}public void toggleMenu(View view){mMenu.toggle();}} package com.example;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Rect;import android.util.DisplayMetrics;import android.view.View;import android.view.WindowManager;/** * Created by tuhao-pc on 2015/12/28. * 获取屏幕相关的辅助类 */public class ScreenUtils {private ScreenUtils() {}/** *获取屏幕的高度 * @param context * @return */public static int getScreenWidth(Context context){WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics outMetrics = new DisplayMetrics();wm.getDefaultDisplay().getMetrics(outMetrics);return outMetrics.widthPixels;}/** * 获取屏幕的高度 * @param context * @return */public static int getScreenHeight(Context context){WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics outMetrics = new DisplayMetrics();wm.getDefaultDisplay().getMetrics(outMetrics);return outMetrics.heightPixels;}/** * 获取手机状态栏的状态 * @param context * @return */public static int getStatusHeight(Context context){int statusHeight = -1;Class<?> clazz = null;try {clazz = Class.forName("com.android.internal.R$dimen");Object object = clazz.newInstance();int height = Integer.parseInt(clazz.getField("status_bar_height").get(object).toString());statusHeight = context.getResources().getDimensionPixelSize(height);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return statusHeight;}/** * 获取当前屏幕截图,包含状态栏 * * @param activity * @return */public static Bitmap snapShotWithStatusBar(Activity activity){View view = activity.getWindow().getDecorView();view.setDrawingCacheEnabled(true);view.buildDrawingCache();Bitmap bmp = view.getDrawingCache();int width = getScreenWidth(activity);int height = getScreenHeight(activity);Bitmap bp = null;bp = Bitmap.createBitmap(bmp, 0, 0, width, height);view.destroyDrawingCache();return bp;}/** * 获取当前屏幕截图,不包含状态栏 * * @param activity * @return */public static Bitmap snapShotWithoutStatusBar(Activity activity){View view = activity.getWindow().getDecorView();view.setDrawingCacheEnabled(true);view.buildDrawingCache();Bitmap bmp = view.getDrawingCache();Rect frame = new Rect();activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);int statusBarHeight = frame.top;int width = getScreenWidth(activity);int height = getScreenHeight(activity);Bitmap bp = null;bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height- statusBarHeight);view.destroyDrawingCache();return bp;}} package com.example;import android.content.Context;import android.content.res.TypedArray;import android.util.AttributeSet;import android.util.TypedValue;import android.view.MotionEvent;import android.view.ViewGroup;import android.widget.HorizontalScrollView;import android.widget.LinearLayout;import com.nineoldandroids.view.ViewHelper;/** * Created by tuhao-pc on 2015/12/28. */public class SlidingMenu extends HorizontalScrollView{private int mScreenWidth;private int mMenuRightPadding;private int mMenuWidth;private int mHalfMenuWidth;private boolean isOpen;private boolean once;private ViewGroup mMenu;private ViewGroup mContent;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);mScreenWidth = ScreenUtils.getScreenWidth(context);TypedArray a = context.getTheme().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:{//默认是50mMenuRightPadding = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,50f,getResources().getDisplayMetrics()));break;}}}a.recycle();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {/** * 显示设置一个宽度 */if(!once){LinearLayout wrapper = (LinearLayout) getChildAt(0);mMenu = (ViewGroup) wrapper.getChildAt(0);mContent = (ViewGroup) wrapper.getChildAt(1);mMenuWidth = mScreenWidth - mMenuRightPadding;mHalfMenuWidth = mMenuWidth/2;mMenu.getLayoutParams().width = mMenuWidth;mContent.getLayoutParams().width = mScreenWidth;}super.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected 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);once = true;}}@Overridepublic boolean onTouchEvent(MotionEvent ev) {int action = ev.getAction();switch (action){// Up时,进行判断,如果显示区域大于菜单宽度一半则完全显示,否则隐藏case MotionEvent.ACTION_UP:{int scrollX = getScrollX();if(scrollX > mHalfMenuWidth){this.smoothScrollTo(mMenuWidth,0);isOpen = false;}else{this.smoothScrollTo(0,0);isOpen = true;}return true;}}return super.onTouchEvent(ev);}/** * 打开菜单 */public void openMenu(){if (isOpen)return;this.smoothScrollTo(0, 0);isOpen = true;}/** * 关闭菜单 */public void closeMenu(){if (isOpen){this.smoothScrollTo(mMenuWidth, 0);isOpen = false;}}/** * 切换菜单状态 */public void toggle(){if (isOpen){closeMenu();} else{openMenu();}}@Overrideprotected void onScrollChanged(int l, int t, int oldl, int oldt){super.onScrollChanged(l, t, oldl, oldt);float scale = l * 1.0f / mMenuWidth;float leftScale = 1 - 0.3f * scale;float rightScale = 0.8f + scale * 0.2f;ViewHelper.setScaleX(mMenu, leftScale);ViewHelper.setScaleY(mMenu, leftScale);ViewHelper.setAlpha(mMenu, 0.6f + 0.4f * (1 - scale));ViewHelper.setTranslationX(mMenu, mMenuWidth * scale * 0.7f);ViewHelper.setPivotX(mContent, 0);ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);ViewHelper.setScaleX(mContent, rightScale);ViewHelper.setScaleY(mContent, rightScale);}}
布局文件和资源文件(xml)
<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tu = "http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"><com.example.SlidingMenuandroid:id="@+id/id_menu"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@mipmap/img_frame_background"tu:rightPadding="20dp"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="fill_parent"android:orientation="horizontal" ><include layout="@layout/layout_menu" /><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="fill_parent"android:background="@mipmap/qq" ><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="toggleMenu"android:text="切换菜单" /></LinearLayout></LinearLayout></com.example.SlidingMenu></LinearLayout> <?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#0000" ><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerVertical="true"android:orientation="vertical" ><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><ImageViewandroid:id="@+id/one"android:layout_width="50dp"android:layout_height="50dp"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:layout_marginTop="20dp"android:src="@mipmap/img_1" /><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:layout_toRightOf="@id/one"android:text="第1个Item"android:textColor="#f0f0f0"android:textSize="20sp" /></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><ImageViewandroid:id="@+id/two"android:layout_width="50dp"android:layout_height="50dp"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:layout_marginTop="20dp"android:src="@mipmap/img_2" /><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:layout_toRightOf="@id/two"android:text="第2个Item"android:textColor="#f0f0f0"android:textSize="20sp" /></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><ImageViewandroid:id="@+id/three"android:layout_width="50dp"android:layout_height="50dp"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:layout_marginTop="20dp"android:src="@mipmap/img_3" /><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:layout_toRightOf="@id/three"android:text="第3个Item"android:textColor="#f0f0f0"android:textSize="20sp" /></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><ImageViewandroid:id="@+id/four"android:layout_width="50dp"android:layout_height="50dp"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:layout_marginTop="20dp"android:src="@mipmap/img_4" /><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:layout_toRightOf="@id/four"android:text="第一个Item"android:textColor="#f0f0f0"android:textSize="20sp" /></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><ImageViewandroid:id="@+id/five"android:layout_width="50dp"android:layout_height="50dp"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:layout_marginTop="20dp"android:src="@mipmap/img_5" /><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:layout_toRightOf="@id/five"android:text="第5个Item"android:textColor="#f0f0f0"android:textSize="20sp" /></RelativeLayout></LinearLayout></RelativeLayout>