Android侧滑显示菜单栏效果的实现

       本文实现AndroidQQ5.0侧滑效果,现在QQ8.8已经不用这种效果了,但是现在最新的酷狗使用的是这种效果。
请看原图:

Android侧滑显示菜单栏效果的实现_第1张图片

向右侧滑或点击切换菜单时的效果:
Android侧滑显示菜单栏效果的实现_第2张图片

实现原理:
其实是使用一个水平布局的ScrollView来放一个线性布局,通过监听屏幕的滑动事件来决定是否显示线性布局里面的侧边栏。

代码:

(一)布局文件activity_my.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:drakeet="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    
    <me.drakeet.qqsliddingmenu.QQSliddingMenu
        android:id="@+id/qqsm"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/img_frame_background"
        drakeet:rigthtPadding="160dp">

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal">
            
            <include layout="@layout/left_menu" />
            
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/qq">

                <TextView
                    android:id="@+id/my_text"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:gravity="center"
                    android:text="主页"
                    android:textColor="#f00"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="10dp"
                    android:layout_marginTop="20dp"
                    android:onClick="toggleMenu"
                    android:text="切换菜单"
                    android:textColor="#fff" />

            RelativeLayout>
        LinearLayout>
    me.drakeet.qqsliddingmenu.QQSliddingMenu>

RelativeLayout>

(二)左边控件的布局文件left_menu.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="vertical">

        <RelativeLayout
            android:id="@+id/left_rl_item1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/iv_1"
                android:layout_width="@dimen/image_dimen"
                android:layout_height="@dimen/image_dimen"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:src="@drawable/img_1" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:layout_toRightOf="@id/iv_1"
                android:text="第一个菜单"
                android:textColor="#ffffff"
                android:textSize="@dimen/text_size" />
        RelativeLayout>

        <RelativeLayout
            android:id="@+id/left_rl_item2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/iv_2"
                android:layout_width="@dimen/image_dimen"
                android:layout_height="@dimen/image_dimen"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:src="@drawable/img_2" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:layout_toRightOf="@id/iv_2"
                android:text="第二个菜单"
                android:textColor="#ffffff"
                android:textSize="@dimen/text_size" />
        RelativeLayout>

        <RelativeLayout
            android:id="@+id/left_rl_item3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/iv_3"
                android:layout_width="@dimen/image_dimen"
                android:layout_height="@dimen/image_dimen"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:src="@drawable/img_3" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:layout_toRightOf="@id/iv_3"
                android:text="第三个菜单"
                android:textColor="#ffffff"
                android:textSize="@dimen/text_size" />
        RelativeLayout>

        <RelativeLayout
            android:id="@+id/left_rl_item4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/iv_4"
                android:layout_width="@dimen/image_dimen"
                android:layout_height="@dimen/image_dimen"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:src="@drawable/img_4" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:layout_toRightOf="@id/iv_4"
                android:text="第四个菜单"
                android:textColor="#ffffff"
                android:textSize="@dimen/text_size" />
        RelativeLayout>

        <RelativeLayout
            android:id="@+id/left_rl_item5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/iv_5"
                android:layout_width="@dimen/image_dimen"
                android:layout_height="@dimen/image_dimen"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:src="@drawable/img_5" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:layout_toRightOf="@id/iv_5"
                android:text="第五个菜单"
                android:textColor="#ffffff"
                android:textSize="@dimen/text_size" />
        RelativeLayout>


    LinearLayout>
RelativeLayout>

       其实上面两个布局文件是可以写在一起的,第一个布局文件include包含第二个布局文件,但是你也可以把第二个布局文件设计成一个碎片,这样所有的点击事件都是在碎片的类中完成的。

(三)滑动事件处理的自定义View的类

package me.drakeet.qqsliddingmenu;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;

import com.nineoldandroids.view.ViewHelper;

/**
 * 水平的滚动视图,实现侧滑功能
 */
public class QQSliddingMenu extends HorizontalScrollView {

    private LinearLayout mWapper;
    private ViewGroup mMenuViewGroup;
    private ViewGroup mContentViewGroup;

    private int mScreenWidth;
    private int mMenuRightPadding = 50;
    private int mMenuWidth;//侧滑菜单栏的宽度

    private boolean mIsOnce = true;
    private boolean mIsOpen;

    /**
     * 构造方法
     */
    public QQSliddingMenu(Context context) {
        this(context, null);
    }

    public QQSliddingMenu(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public QQSliddingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        mScreenWidth = displayMetrics.widthPixels;
        TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.QQSliddingMenu, defStyleAttr, 0);
        int n = typedArray.length();
        for (int i = 0; i < n; i++) {
            int attr = typedArray.getIndex(i);
            switch (attr) {
                case R.styleable.QQSliddingMenu_rigthtPadding:
                    mMenuRightPadding = typedArray.getDimensionPixelSize(
                            attr,
                            (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics())
                    );
                    break;
                default:
                    break;
            }
        }
        typedArray.recycle();
    }

    /**
     * 测量布局
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mIsOnce) {
            mWapper = (LinearLayout) getChildAt(0);
            mMenuViewGroup = (ViewGroup) mWapper.getChildAt(0);
            mContentViewGroup = (ViewGroup) mWapper.getChildAt(1);
            mMenuWidth = mMenuViewGroup.getLayoutParams().width = mScreenWidth - mMenuRightPadding;
            mContentViewGroup.getLayoutParams().width = mScreenWidth;
            mIsOnce = 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);
        if (changed) {
            this.scrollTo(mMenuWidth, 0);
        }
    }

    /**
     * 事件响应
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_UP:
                int scrollX = getScrollX();
                if (scrollX >= mMenuWidth / 2) {
                    smoothScrollTo(mMenuWidth, 0);
                    mIsOpen = false;
                } else {
                    smoothScrollTo(0, 0);
                    mIsOpen = true;
                }
                return true;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 打开菜单栏
     */
    public void openMenu() {
        if (mIsOpen)
            return;
        smoothScrollTo(0, 0);
        mIsOpen = true;
    }

    /**
     * 关闭菜单栏
     */
    public void closeMenu() {
        if (!mIsOpen)
            return;
        smoothScrollTo(mMenuWidth, 0);
        mIsOpen = false;
    }

    /**
     * 切换菜单
     */
    public void toggleMenu() {
        if (mIsOpen)
            closeMenu();
        else
            openMenu();
    }

    /**
     * 页面滑动的距离的改变
     */
    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        float scale = l * 1.0f / mMenuWidth; // l: 1.0 ~ 0
        ViewHelper.setTranslationX(mMenuViewGroup, mMenuWidth * scale * 0.7f);

        float rightScale = 0.7f + 0.3f * scale;
        ViewHelper.setPivotX(mContentViewGroup, 0);
        ViewHelper.setPivotY(mContentViewGroup, mContentViewGroup.getHeight() / 2);
        ViewHelper.setScaleX(mContentViewGroup, rightScale);
        ViewHelper.setScaleY(mContentViewGroup, rightScale);

        float leftScale = 1.0f - 0.3f * scale;
        ViewHelper.setScaleX(mMenuViewGroup, leftScale);
        ViewHelper.setScaleY(mMenuViewGroup, leftScale);

        float leftAlpha = 0.1f + 0.9f * (1 - scale);
        ViewHelper.setAlpha(mMenuViewGroup, leftAlpha);
    }
}

(四)主方法的类

package me.drakeet.qqsliddingmenu;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;

/**
 * 侧边栏的示例
 */
public class MyActivity extends AppCompatActivity implements View.OnClickListener {
    //侧滑的自定义View对象
    private QQSliddingMenu mQQSliddingMenu;
    TextView text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        mQQSliddingMenu = (QQSliddingMenu) findViewById(R.id.qqsm);
        text = (TextView) findViewById(R.id.my_text);
        initLeftItem();
    }

    /**
     * 给左边的侧滑条目设置监听事件
     */
    private void initLeftItem() {
        RelativeLayout rl1 = (RelativeLayout) findViewById(R.id.left_rl_item1);
        RelativeLayout rl2 = (RelativeLayout) findViewById(R.id.left_rl_item2);
        RelativeLayout rl3 = (RelativeLayout) findViewById(R.id.left_rl_item3);
        RelativeLayout rl4 = (RelativeLayout) findViewById(R.id.left_rl_item4);
        RelativeLayout rl5 = (RelativeLayout) findViewById(R.id.left_rl_item5);
        rl1.setOnClickListener(this);
        rl2.setOnClickListener(this);
        rl3.setOnClickListener(this);
        rl4.setOnClickListener(this);
        rl5.setOnClickListener(this);

    }


    /**
     * 点击切换菜单按钮的监听事件
     */
    public void toggleMenu(View view) {
        mQQSliddingMenu.toggleMenu();
    }

    /**
     * 点击左边的菜单栏的条目的监听事件
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.left_rl_item1:
                text.setText("选择了第一个按钮");
                break;
            case R.id.left_rl_item2:
                text.setText("选择了第二个按钮");
                break;
            case R.id.left_rl_item3:
                text.setText("选择了第三个按钮");
                break;
            case R.id.left_rl_item4:
                text.setText("选择了第四个按钮");
                break;
            case R.id.left_rl_item5:
                text.setText("选择了第五个按钮");
                break;
        }
        //切换菜单
        mQQSliddingMenu.toggleMenu();
    }
}

      到这里一个QQ5.0侧拉效果的功能就实现了,其实最主要的就是那个自定义的View,这个工具类是可以直接拿来使用的。
左边的菜单条目也是有点击效果的:
Android侧滑显示菜单栏效果的实现_第3张图片
点击第三个菜单栏的条目显得的效果:
Android侧滑显示菜单栏效果的实现_第4张图片
这里只是简单显示右边的效果,实际中可以把右边换成一个新的页面。
     这里如果变成现在最小版本的QQ效果,只要侧滑时,Y轴方向的大小不改变就可以了。
这里注销两句话,就实现了!
//ViewHelper.setPivotY(mContentViewGroup, mContentViewGroup.getHeight() / 2);
// ViewHelper.setScaleY(mContentViewGroup, rightScale);
如图:
Android侧滑显示菜单栏效果的实现_第5张图片
改变后的效果,侧滑时:

Android侧滑显示菜单栏效果的实现_第6张图片
侧滑后:
Android侧滑显示菜单栏效果的实现_第7张图片
      最后还得说一下,在实际开发中,如果开发的是一个比较大的程序,比如QQ这种,肯定是要把左边的菜单栏设计成一个碎片fragment,右边的布局是一个帧布局FrameLayout,用来动态创建碎片。这样所有的逻辑操作都是在对应的碎片的类Fragment中实现,避免逻辑混乱。
下面提供一下程序设计的源码下载地址:
http://download.csdn.net/detail/wenzhi20102321/9723485

你可能感兴趣的:(android,UI)