Android使用DrawerLayout实现仿QQ双向侧滑菜单

时间:2021-07-18 14:11:42

1、概述

之前写了一个android 高仿 qq5.0 侧滑菜单效果 自定义控件来袭 ,恰逢qq5.2又加了一个右侧菜单,刚好看了下drawerlayout,一方面官方的东西,我都比较感兴趣;另一方面,这玩意用起来的确方便,于是简单写了个demo,高仿qq5.2双向侧滑,分享给大家。

首先看看效果图:

Android使用DrawerLayout实现仿QQ双向侧滑菜单

drawerlayout用起来真的很方便,下面一起看看用法~

2、drawerlayout的使用

直接将drawerlayout作为根布局,然后其内部第一个view为内容区域,第二个view为左侧菜单,第三个view为右侧侧滑菜单,当前第三个是可选的。

第一个view的宽高应当设置为match_parent,当然了,这也理所当然。

第二、三个view需要设置android:layout_gravity="left",和android:layout_gravity="right"且一搬高度设置为match_parent,宽度为固定值,即侧滑菜单的宽度。

按照上面的描述写个布局文件,然后设置给activity就添加好了左右侧滑了,是不是很简单~~~

比如我们的布局文件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<android.support.v4.widget.drawerlayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/id_drawerlayout"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="@drawable/img_frame_background" >
 
  <relativelayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/qq" >
 
    <button
      android:layout_width="40dp"
      android:layout_height="30dp"
       android:layout_margintop="10dp"
      android:layout_alignparentright="true"
      android:background="@drawable/youce"
      android:onclick="openrightmenu" />
  </relativelayout>
 
  <fragment
    android:id="@+id/id_left_menu"
    android:name="com.zhy.demo_zhy_17_drawerlayout.menuleftfragment"
    android:layout_width="200dp"
    android:layout_height="match_parent"
    android:layout_gravity="left"
    android:tag="left" />
 
  <fragment
    android:id="@+id/id_right_menu"
    android:name="com.zhy.demo_zhy_17_drawerlayout.menurightfragment"
    android:layout_width="100dp"
    android:layout_height="match_parent"
    android:layout_gravity="right"
    android:tag="right" />
 
</android.support.v4.widget.drawerlayout>

这里我们的主内容区域为relativelayout

菜单用的两个fragment,左侧为200dp,右侧为100dp;

好了,看了我们的布局文件,接下来看下我们的详细代码。

3、代码是最好的老师

1、menuleftfragment

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.zhy.demo_zhy_17_drawerlayout;
 
import android.os.bundle;
import android.support.v4.app.fragment;
import android.view.layoutinflater;
import android.view.view;
import android.view.viewgroup;
 
public class menuleftfragment extends fragment
{
 
  @override
  public view oncreateview(layoutinflater inflater, viewgroup container,
      bundle savedinstancestate)
  {
    return inflater.inflate(r.layout.layout_menu, container, false);
  }
}

对应的布局文件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
<?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="#00000000" >
 
  <linearlayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centervertical="true"
    android:orientation="vertical" >
 
    <relativelayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content" >
 
      <imageview
        android: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="@drawable/img_1" />
 
      <textview
        android: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>
 
    <relativelayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content" >
 
      <imageview
        android: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="@drawable/img_2" />
 
      <textview
        android: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>
 
    <relativelayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content" >
 
      <imageview
        android: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="@drawable/img_3" />
 
      <textview
        android: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>
 
    <relativelayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content" >
 
      <imageview
        android: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="@drawable/img_4" />
 
      <textview
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_centervertical="true"
        android:layout_marginleft="20dp"
        android:layout_torightof="@id/four"
        android:text="第4个item"
        android:textcolor="#f0f0f0"
        android:textsize="20sp" />
    </relativelayout>
 
    <relativelayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content" >
 
      <imageview
        android: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="@drawable/img_5" />
 
      <textview
        android: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>

其实就是堆出来的布局~~没撒意思~

2、menurightfragment

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.zhy.demo_zhy_17_drawerlayout;
 
import android.os.bundle;
import android.support.v4.app.fragment;
import android.view.layoutinflater;
import android.view.view;
import android.view.viewgroup;
 
public class menurightfragment extends fragment
{
 
  @override
  public view oncreateview(layoutinflater inflater, viewgroup container,
      bundle savedinstancestate)
  {
    return inflater.inflate(r.layout.menu_layout_right, container, false);
  }
}

对应布局文件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:gravity="center_vertical"
  android:orientation="vertical" >
 
  <linearlayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centervertical="true"
    android:layout_gravity="center_vertical"
    android:layout_marginbottom="20dp"
    android:orientation="vertical" >
 
    <imageview
      android:layout_width="60dp"
      android:layout_height="60dp"
      android:layout_gravity="center"
      android:src="@drawable/wode" />
 
    <textview
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:gravity="center"
      android:text="扫一扫"
      android:textcolor="#ffffff" />
  </linearlayout>
 
  <linearlayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centervertical="true"
    android:layout_gravity="center_vertical"
    android:layout_marginbottom="20dp"
    android:orientation="vertical" >
 
    <imageview
      android:layout_width="60dp"
      android:layout_height="60dp"
      android:layout_gravity="center"
      android:src="@drawable/saoma" />
 
    <textview
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:gravity="center"
      android:text="讨论组"
      android:textcolor="#ffffff" />
  </linearlayout>
 
  <linearlayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centervertical="true"
    android:layout_gravity="center_vertical"
    android:layout_marginbottom="20dp"
    android:orientation="vertical" >
 
    <imageview
      android:layout_width="60dp"
      android:layout_height="60dp"
      android:layout_gravity="center"
      android:src="@drawable/wode" />
 
    <textview
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:gravity="center"
      android:text="扫一扫"
      android:textcolor="#ffffff" />
  </linearlayout>
 
  <linearlayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centervertical="true"
    android:layout_gravity="center_vertical"
    android:layout_marginbottom="20dp"
    android:orientation="vertical" >
 
    <imageview
      android:layout_width="60dp"
      android:layout_height="60dp"
      android:layout_gravity="center"
      android:src="@drawable/saoma" />
 
    <textview
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:gravity="center"
      android:text="讨论组"
      android:textcolor="#ffffff" />
  </linearlayout>
 
</linearlayout>

依旧很简单,除了图标比较难找以外~~

3、mainactivity
mainactivity的布局文件已经贴过了~~

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package com.zhy.demo_zhy_17_drawerlayout;
 
import android.os.bundle;
import android.support.v4.app.fragmentactivity;
import android.support.v4.widget.drawerlayout;
import android.support.v4.widget.drawerlayout.drawerlistener;
import android.view.gravity;
import android.view.view;
import android.view.window;
 
import com.nineoldandroids.view.viewhelper;
 
public class mainactivity extends fragmentactivity
{
 
  private drawerlayout mdrawerlayout;
 
  @override
  protected void oncreate(bundle savedinstancestate)
  {
    super.oncreate(savedinstancestate);
    requestwindowfeature(window.feature_no_title);
    setcontentview(r.layout.activity_main);
 
    initview();
    initevents();
 
  }
 
  public void openrightmenu(view view)
  {
    mdrawerlayout.opendrawer(gravity.right);
    mdrawerlayout.setdrawerlockmode(drawerlayout.lock_mode_unlocked,
        gravity.right);
  }
 
  private void initevents()
  {
    mdrawerlayout.setdrawerlistener(new drawerlistener()
    {
      @override
      public void ondrawerstatechanged(int newstate)
      {
      }
 
      @override
      public void ondrawerslide(view drawerview, float slideoffset)
      {
        view mcontent = mdrawerlayout.getchildat(0);
        view mmenu = drawerview;
        float scale = 1 - slideoffset;
        float rightscale = 0.8f + scale * 0.2f;
 
        if (drawerview.gettag().equals("left"))
        {
 
          float leftscale = 1 - 0.3f * scale;
 
          viewhelper.setscalex(mmenu, leftscale);
          viewhelper.setscaley(mmenu, leftscale);
          viewhelper.setalpha(mmenu, 0.6f + 0.4f * (1 - scale));
          viewhelper.settranslationx(mcontent,
              mmenu.getmeasuredwidth() * (1 - scale));
          viewhelper.setpivotx(mcontent, 0);
          viewhelper.setpivoty(mcontent,
              mcontent.getmeasuredheight() / 2);
          mcontent.invalidate();
          viewhelper.setscalex(mcontent, rightscale);
          viewhelper.setscaley(mcontent, rightscale);
        } else
        {
          viewhelper.settranslationx(mcontent,
              -mmenu.getmeasuredwidth() * slideoffset);
          viewhelper.setpivotx(mcontent, mcontent.getmeasuredwidth());
          viewhelper.setpivoty(mcontent,
              mcontent.getmeasuredheight() / 2);
          mcontent.invalidate();
          viewhelper.setscalex(mcontent, rightscale);
          viewhelper.setscaley(mcontent, rightscale);
        }
 
      }
 
      @override
      public void ondraweropened(view drawerview)
      {
      }
 
      @override
      public void ondrawerclosed(view drawerview)
      {
        mdrawerlayout.setdrawerlockmode(
            drawerlayout.lock_mode_locked_closed, gravity.right);
      }
    });
  }
 
  private void initview()
  {
    mdrawerlayout = (drawerlayout) findviewbyid(r.id.id_drawerlayout);
    mdrawerlayout.setdrawerlockmode(drawerlayout.lock_mode_locked_closed,
        gravity.right);
  }
 
}

嗯,代码基本没什么注释~~维撒呢?是因为的确没什么好注释的。

提几点:

1、为了模拟qq的右侧菜单需要点击才能出现,所以在初始化drawerlayout的时候,使用了mdrawerlayout.setdrawerlockmode(drawerlayout.lock_mode_locked_closed,gravity.right);意思是只有编程才能将其弹出。

然后在弹出以后,需要让手势可以滑动回去,所以在openrightmenu中又编写了:

mdrawerlayout.setdrawerlockmode(drawerlayout.lock_mode_unlocked,gravity.right); unlock了一下。

最后在ondrawerclosed回调中,继续设置mdrawerlayout.setdrawerlockmode(drawerlayout.lock_mode_locked_closed,gravity.right);

2、动画效果

动画用了nineoldandroids,关于动画各种偏移量、缩放比例的计算请参考android 高仿 qq5.0 侧滑菜单效果 自定义控件来袭 基本是一致的,唯一的不同的地方,给content设置了viewhelper.settranslationx(mcontent, mmenu.getmeasuredwidth() * (1 - scale));让content在菜单的右侧,默认情况下menu在菜单之上,所以我们根据菜单划出的距离给content设置x方向的偏移量。

好了,其实看到可以这么做,基本上任何的侧滑菜单效果都能写出来了。有兴趣的话,可以拿drawerlayout实现这篇博客的所有效果:android 实现形态各异的双向侧滑菜单 自定义控件来袭 。

3、setdrawerlistener

通过代码也能看出来,可以使用setdrawerlistener监听菜单的打开与关闭等等。这里对于当前操作是哪个菜单的判断是通过tag判断的,我觉得使用gravity应该也能判断出来~~

好了,没撒了,由于drawerlayout默认只能从边界划出菜单,但是qq划出菜单的手势区域比较大,大家有兴趣,可以重写activity的ontouchevent,在里面判断,如果是左右滑动手势神马的,弹出菜单,应该不麻烦~~~