服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Android自定义实现侧滑菜单效果

Android自定义实现侧滑菜单效果

2022-09-21 15:15oblivion0001 Android

这篇文章主要为大家详细介绍了Android自定义实现侧滑菜单效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了Android自定义实现侧滑菜单的具体代码,供大家参考,具体内容如下

实现原理:继承ViewGroup控件要显示到界面上需要重写OnMeature()
OnLayout(),因此在实现OnLayout()的时候,将菜单界面划出到屏幕左侧,动态改变菜单界面距离scrollXto()左边界的距离就能实现滑动效果。

1.继承ViewGroup
2.事件分发机制
3.状态监听

在主界面中添加两个子控件

?
1
2
3
4
5
6
7
8
9
10
11
12
<com.oblivion.ui.SlideMenu xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/sliding_menu"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
 
  <!-- 在SlidingMenu中的索引0 -->
  <include layout="@layout/menu" />
 
  <!-- 在SlidingMenu中的索引1 -->
  <include layout="@layout/main" />
 
</com.oblivion.ui.SlideMenu>

menu菜单布局

?
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
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="240dp"
  android:layout_height="match_parent"
  android:background="@drawable/menu_bg">
 
  <LinearLayout
    android:layout_width="240dp"
    android:layout_height="wrap_content"
    android:orientation="vertical">
 
    <TextView
      android:id="@+id/tv_news"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:background="@drawable/select_menu"
      android:clickable="true"
      android:drawableLeft="@drawable/tab_news"
      android:drawablePadding="10dp"
      android:text="新闻" />
 
    <TextView
      android:id="@+id/tv_read"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:drawableLeft="@drawable/tab_read"
      android:drawablePadding="10dp"
      android:text="订阅" />
 
    <TextView
      android:id="@+id/tv_local"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:drawableLeft="@drawable/tab_local"
      android:drawablePadding="10dp"
      android:text="本地" />
 
    <TextView
      android:id="@+id/tv_ties"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:drawableLeft="@drawable/tab_ties"
      android:drawablePadding="10dp"
      android:text="跟帖" />
 
    <TextView
      android:id="@+id/tv_pics"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:drawableLeft="@drawable/tab_pics"
      android:drawablePadding="10dp"
      android:text="图片" />
 
    <TextView
      android:id="@+id/tv_ugc"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:drawableLeft="@drawable/tab_ugc"
      android:drawablePadding="10dp"
      android:text="话题" />
 
    <TextView
      android:id="@+id/tv_vote"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:drawableLeft="@drawable/tab_vote"
      android:drawablePadding="10dp"
      android:text="投票" />
 
    <TextView
      android:id="@+id/tv_focus"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:drawableLeft="@drawable/tab_focus"
      android:drawablePadding="10dp"
      android:text="焦点" />
  </LinearLayout>
</ScrollView>

显示界面布局

?
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
<?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:orientation="vertical">
 
  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/top_bar_bg"
    android:orientation="horizontal">
 
    <ImageView
      android:id="@+id/iv_showmenu"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/main_back" />
 
    <View
      android:layout_width="1dp"
      android:layout_height="match_parent"
      android:background="@drawable/top_bar_divider"></View>
 
    <TextView
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:gravity="center"
      android:text="新闻首页"
      android:textColor="#ffffff"
      android:textSize="30sp" />
  </LinearLayout>
 
  <TextView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:text="我操,这么low"
    android:textColor="#000000"
    android:textSize="20sp" />
 
 
</LinearLayout>

实现原理:继承ViewGroup控件要显示到界面上需要重写OnMeature() OnLayout(),因此在实现OnLayout()的时候,将菜单界面划出到屏幕左侧,动态改变菜单界面距离scrollXto()左边界的距离就能实现滑动效果。

实现onMeasure()和onLayout()方法,对控件进行布局

?
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
/**
   * 测量布局中的控件
   *
   * @param widthMeasureSpec
   * @param heightMeasureSpec
   */
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);//测量自身宽高
    //得到menu界面
    menuView = getChildAt(0);
    menuViewWidth = menuView.getLayoutParams().width;
    //得到main界面
    mainView = getChildAt(1);
    //设定menuView的宽------不用setMeasure...
    menuView.measure(MeasureSpec.makeMeasureSpec(menuViewWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
    //设定mainView的宽
    mainView.measure(widthMeasureSpec, heightMeasureSpec);
  }
 
  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
 
    int menuleft = -menuViewWidth;//menu设定的left
    int menuright = 0;//menu设定的right
    int menutop = 0;//menu设定的top
    int menubottom = b - t;//menu设定的bottom
    //布局menuView 控件xx2
    menuView.layout(menuleft, menutop, menuright, menubottom);
    int mainleft = 0;//main设定的left
    int mainright = r - l;//main设定的right
    int maintop = 0;//main设定的top
    int mainbottom = b - t;//main设定的bottom
    //布局mainView ---------------控件.....你妈逼方向---------方向是left,top,right,bottom
    mainView.layout(mainleft, maintop, mainright, mainbottom);
    System.out.println(menuViewWidth--);//原来这这里减减了;
 
  }

通过onTouch()方法,以及scrollX()和getScrollX()方法获取边界值,动态改变去实现滑动。
这里需要注意的是scrollX(),getScrollX()得到的值是相对于布局起始点的,所以需要重新封装;
平滑动画,需要在构造函数中创建一个Scroll 类,然后通过ComplentScroll..方法,判断设定的平滑动画是否结束。

最后通过,动画结束后的边界值,判断是否打开,关闭状态。

 

?
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
/**
  * 由于系统scrollTo是取反操作,所以需要封装一下
  *
  * @param distance
  */
 private void scrollTo(int distance) {
   super.scrollTo(-distance, 0);
 }
 
 public int getMyScrollX() {
   return -getScrollX();
 }
 
 /**
  * 控件触莫状态
  *
  * @param event
  * @return
  */
 @Override
 public boolean onTouchEvent(MotionEvent event) {
   switch (event.getAction()) {
     case MotionEvent.ACTION_DOWN:
       //记录按下点
       down_dot = (int) event.getX();
       System.out.println(down_dot);
       break;
     case MotionEvent.ACTION_MOVE:
       int move_dot = (int) event.getX();
       //动态的移动点和按下点的间距绝对值
       move2down_distance = move_dot - down_dot;
       //移动间距与上次抬起的点
       int lastUp_dot = move2down_distance + up_dot;
       // 控制边界
       if (lastUp_dot >= menuViewWidth) {
         lastUp_dot = menuViewWidth;
       } else if (lastUp_dot <= 0) {
         lastUp_dot = 0;
       }
       //设定移动后的距离
       scrollTo(lastUp_dot);
       break;
     case MotionEvent.ACTION_UP:
       //当前抬起手指点
       up_dot = (int) event.getX();
       //设定最终的状态
       setFinalScroll();
       break;
   }
   return true;//将事件消费掉
 }
 
 /**
  * 当手指抬起后,记录最终的状态;
  */
 private void setFinalScroll() {
   //得到当前距离左边界的距离
   currrentScroll = getMyScrollX();
   if (currrentScroll >= menuViewWidth / 2) {
     //scrollTo(menuViewWidth);
     rightAnimation();
   } else {
     leftAnimation();
 
   }
 }
 
 /**
  * 平滑向左的移动动画
  */
 private void leftAnimation() {
   //scrollTo(0);
   int dx = 0 - currrentScroll;//要移动的距离
   //设定平滑动画
   msScroller.startScroll(currrentScroll, 0, dx, 0, 300);
   invalidate();
   //设定一下抬起点
   up_dot = 0;
   //调用接口的关闭状态
   mOnDragStateListener.onDragClose();
 }
 /**
  * 平滑向右移动的动画
  */
 private void rightAnimation() {
   int dx = menuViewWidth - currrentScroll;//要移动的距离
   //设定平滑动画
   msScroller.startScroll(currrentScroll, 0, dx, 0, 300);
   invalidate();
   //设定一下抬起点
   up_dot = menuViewWidth;
   //调用接口的开启状态
   mOnDragStateListener.onDragOpen();
 }
 
 /**
  * 平滑移动动画是否结束
  */
 @Override
 public void computeScroll() {
   super.computeScroll();
   if (msScroller.computeScrollOffset()) {
     int currX = msScroller.getCurrX();//模拟出来的数值
     scrollTo(currX);
     invalidate();
   }
 }

创建监听,以及回调接口

?
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
/**
  * 拖拽的监听
  */
 public void setOnDragStateListener(onDragStateListener listener) {
   mOnDragStateListener = listener;
 }
 
 /**
  * 回调修改状态
  *
  * @param dragState
  */
 public void setStateChange(boolean dragState) {
   if (dragState) {
     currrentScroll = 0;
     rightAnimation();
   } else {
     currrentScroll = menuViewWidth;
     leftAnimation();
   }
 }
 
 
 /**
  * 创建拖拽的回调接口
  */
 public interface onDragStateListener {
   /**
    * 被拖拽开
    */
   void onDragOpen();
 
   /**
    * 被关闭
    */
   void onDragClose();
 }

主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
iv_showmenu.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        //图片点击后触发改变状态
        sliding_menu.setStateChange(dragState);
      }
    });
    sliding_menu.setOnDragStateListener(new SlideMenu.onDragStateListener() {
      @Override
      public void onDragOpen() {
        ToastUtils.setToast(getApplicationContext(), "open");
        dragState = false;
        tv_news.setSelected(true);
        tv_news.setTextColor(Color.BLUE);
      }
 
      @Override
      public void onDragClose() {
        ToastUtils.setToast(getApplicationContext(), "close");
        dragState = true;
        tv_news.setSelected(false);
        tv_news.setTextColor(Color.WHITE);
      }
    });
    tv_news.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        ToastUtils.setToast(getApplicationContext(), tv_news.getText().toString());
      }
    });
  }

github源码地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/qq_16666847/article/details/52940636

延伸 · 阅读

精彩推荐