Android 高级控件SlidingMenu视图的创建

文章来自http://www.cnblogs.com/lichenwei/p/4111252.html , 请尊重作者的劳动成果,向作者表示感谢

1、所谓的SlidingMenu,就是像下面这样的QQ菜单页面视图:

相信大家都不陌生,下面我们自来开发一个这样的SlidingView组件,实际上非常的简单,我们主要的工作就是创建一个自定的HorizontalScrollView,之后重新定义这个HorizontalScrollView的显示方式就可以了

2、我们最终实现的效果是:

      

整体的思路是这样的:

①首先自定义一个HorizontalScrollView组件,称为:MyHorizontalScrollView,定义一下这个组件的显示方式,当然其中必然使用一些和缩放有关的动画设置,我们可以使用第三方的NineOldAndroids开源项目中提供的相关类,实现这样的功能是非常的简单的

②只用这个组件和使用普通的HorizontalScrollView组件一样,我们将一个横向的LinearLayout布局放在这个MyHorizontalScrollView之中

③之后在上面的横向布局中放入一次放入两个布局组件,一个布局组件用于显示左边的菜单视图,一个用于显示右边的内容视图

3、好了,废话少说,直接上代码:

菜单视图文件 menu.xml文件

  1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2     xmlns:tools="http://schemas.android.com/tools"
  3     android:layout_width="match_parent"
  4     android:layout_height="match_parent" >
  5 
  6     <LinearLayout 
  7         android:layout_width="match_parent"
  8         android:layout_height="match_parent"
  9         android:orientation="vertical">
 10         
 11         <RelativeLayout 
 12             android:layout_width="match_parent"
 13             android:layout_height="wrap_content">
 14             
 15             <ImageView 
 16                 android:id="@+id/image_1"
 17                 android:layout_width="60dp"
 18                 android:layout_height="60dp"
 19                 android:layout_centerVertical="true"  //设置为垂直居中
 20                 android:layout_marginStart="20dp"
 21                 android:layout_marginTop="20dp"
 22                 android:src="@drawable/img_1"/>
 23             
 24             <TextView 
 25                 android:id="@+id/textview_1"
 26                 android:layout_width="wrap_content"
 27                 android:layout_height="wrap_content"
 28                 android:layout_centerVertical="true"
 29                 android:layout_toEndOf="@id/image_1"
 30                 android:layout_marginStart="20dp"
 31                 android:layout_marginTop="20dp"
 32                 android:text="@string/menu_1"
 33                 android:textSize="20sp"
 34                 android:textColor="@android:color/white"/>
 35             
 36         </RelativeLayout>
 37         
 38        <RelativeLayout 
 39             android:layout_width="match_parent"
 40             android:layout_height="wrap_content">
 41             
 42             <ImageView 
 43                 android:id="@+id/image_2"
 44                 android:layout_width="60dp"
 45                 android:layout_height="60dp"
 46                 android:layout_centerVertical="true"
 47                 android:layout_marginStart="20dp"
 48                 android:layout_marginTop="20dp"
 49                 android:src="@drawable/img_2"/>
 50             
 51             <TextView 
 52                 android:id="@+id/textview_2"
 53                 android:layout_width="wrap_content"
 54                 android:layout_height="wrap_content"
 55                 android:layout_centerVertical="true"
 56                 android:layout_toEndOf="@id/image_2"
 57                 android:layout_marginStart="20dp"
 58                 android:layout_marginTop="20dp"
 59                 android:text="@string/menu_2"
 60                 android:textSize="20sp"
 61                 android:textColor="@android:color/white"/>
 62             
 63         </RelativeLayout>
 64         
 65        <RelativeLayout 
 66            android:layout_width="match_parent"
 67             android:layout_height="wrap_content">
 68             
 69             <ImageView 
 70                 android:id="@+id/image_3"
 71                 android:layout_width="60dp"
 72                 android:layout_height="60dp"
 73                 android:layout_centerVertical="true"
 74                 android:layout_marginStart="20dp"
 75                 android:layout_marginTop="20dp"
 76                 android:src="@drawable/img_3"/>
 77             
 78             <TextView 
 79                 android:id="@+id/textview_3"
 80                 android:layout_width="wrap_content"
 81                 android:layout_height="wrap_content"
 82                 android:layout_centerVertical="true"
 83                 android:layout_toEndOf="@id/image_3"
 84                 android:layout_marginStart="20dp"
 85                 android:layout_marginTop="20dp"
 86                 android:text="@string/menu_3"
 87                 android:textSize="20sp"
 88                 android:textColor="@android:color/white"/>
 89             
 90         </RelativeLayout>
 91         <RelativeLayout 
 92            android:layout_width="match_parent"
 93             android:layout_height="wrap_content">
 94             
 95             <ImageView 
 96                 android:id="@+id/image_4"
 97                 android:layout_width="60dp"
 98                 android:layout_height="60dp"
 99                 android:layout_centerVertical="true"
100                 android:layout_marginStart="20dp"
101                 android:layout_marginTop="20dp"
102                 android:src="@drawable/img_4"/>
103             
104             <TextView 
105                 android:id="@+id/textview_4"
106                 android:layout_width="wrap_content"
107                 android:layout_height="wrap_content"
108                 android:layout_centerVertical="true"
109                 android:layout_toEndOf="@id/image_4"
110                 android:layout_marginStart="20dp"
111                 android:layout_marginTop="20dp"
112                 android:text="@string/menu_4"
113                 android:textSize="20sp"
114                 android:textColor="@android:color/white"/>
115             
116         </RelativeLayout>
117         
118          <RelativeLayout 
119             android:layout_width="match_parent"
120             android:layout_height="wrap_content">
121             
122             <ImageView 
123                 android:id="@+id/image_5"
124                 android:layout_width="60dp"
125                 android:layout_height="60dp"
126                 android:layout_centerVertical="true"
127                 android:layout_marginStart="20dp"
128                 android:layout_marginTop="20dp"
129                 android:src="@drawable/img_5"/>
130             
131             <TextView 
132                 android:id="@+id/textview_5"
133                 android:layout_width="wrap_content"
134                 android:layout_height="wrap_content"
135                 android:layout_centerVertical="true"
136                 android:layout_toEndOf="@id/image_5"
137                 android:layout_marginStart="20dp"
138                 android:layout_marginTop="20dp"
139                 android:text="@string/menu_5"
140                 android:textSize="20sp"
141                 android:textColor="@android:color/white"/>
142             
143         </RelativeLayout>
144         
145     </LinearLayout>
146     
147 
148 </RelativeLayout>


主布局文件 activity.xml文件

 

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent" 
 5     android:background="@drawable/img_frame_background">
 6     
 7     <com.penglee.slidingmenu_test.MyHorizontalScrollView 
 8         android:layout_width="match_parent"
 9         android:layout_height="match_parent"
10         android:scrollbars="none">
11         
12         <LinearLayout 
13             android:layout_width="match_parent"
14             android:layout_height="match_parent"
15             android:orientation="horizontal">
16             
17             <include layout="@layout/menu"/>
18             <LinearLayout
19                 android:layout_width="match_parent"
20                 android:layout_height="match_parent"
21                 android:background="@drawable/qq"/>
22             也就是说内容视图我们只是使用了一张QQ图片
23         </LinearLayout>
24         
25     </com.penglee.slidingmenu_test.MyHorizontalScrollView>
26 
27 </RelativeLayout>

 主Activity只要加载上面的布局文件就好了,不在多说,下面来看看MyhorizontalScrollView代码

  1 package com.penglee.slidingmenu_test;
  2 
  3 import android.content.Context;
  4 import android.util.AttributeSet;
  5 import android.util.DisplayMetrics;
  6 import android.util.Log;
  7 import android.util.TypedValue;
  8 import android.view.MotionEvent;
  9 import android.view.ViewGroup;
 10 import android.view.WindowManager;
 11 import android.widget.HorizontalScrollView;
 12 import android.widget.LinearLayout;
 13 import com.nineoldandroids.view.ViewHelper;   这是一个第三方的开源的包,我们需要导入一下 只有ViewHelper要用到这个第三方包
 14 
 15 public class MyHorizontalScrollView extends HorizontalScrollView{
 16     
 17     private int screenWidth ;  //屏幕的宽度
 18     private int myMenuPaddingRight = 50 ; //向右活动结束时菜单与屏幕右侧的距离
 19     private int myMenuWidth ; // 当Menu视图显示最大化时的宽度 , 也就是屏幕的宽度减去myMenuPaddingRight
 20     private boolean once = false ; //控制onMeasure中的代码只执行一次就行了,避免程序的资源浪费
 21     private LinearLayout linearLayout ;  // 在HorizontalScrollView有个LinearLayout,对照一下上面的主布局文件
 22     private ViewGroup myMenu ;  // 在HorizontalScrollView中的LinearLayout中添加了菜单  , 对照主布局文件
 23     private ViewGroup myContent ;  // 在HorizontalScrollView中的LinearLayout中添加了内容视图组件, 对照主布局文件
 24     
 25     
 26     //注意自定义组件的构造方法的选择和使用,否则就会崩了,之前在自定义的View中已经说过这个问题了
 27     public MyHorizontalScrollView(Context context, AttributeSet attrs) {
 28         super(context, attrs);
 29     
 30              // 获取屏幕宽度
 31              WindowManager windowManager = (WindowManager) context
 32                             .getSystemService(Context.WINDOW_SERVICE);
 33              DisplayMetrics outMetrics = new DisplayMetrics();
 34              windowManager.getDefaultDisplay().getMetrics(outMetrics);
 35              screenWidth = outMetrics.widthPixels;// 屏幕宽度
 36              
 37               // 将单位转换为dp,即为50dp
 38               myMenuPaddingRight = (int) TypedValue.applyDimension(
 39               TypedValue.COMPLEX_UNIT_DIP,myMenuPaddingRight , context.getResources()
 40                               .getDisplayMetrics());
 41              
 42     }
 43     
 44     /**
 45      * 
 46      * 设置一下MyHorizontalScrollView中添加的各个组件的大小
 47      * 
 48      * */
 49     @Override
 50     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 51          super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 52          if (!once) {//使其只调用一次
 53               // this指的是HorizontalScrollView,获取各个元素
 54                linearLayout = (LinearLayout) this.getChildAt(0);// 第一个子元素,对应着主布局文件中的MyHorizontalScrollView中的组件看,就会一目了然
 55                myMenu = (ViewGroup) linearLayout.getChildAt(0);// HorizontalScrollView下LinearLayout的第一个子元素
 56                myContent = (ViewGroup) linearLayout.getChildAt(1);// HorizontalScrollView下LinearLayout的第二个子元素
 57       
 58                // 设置子View的宽高,高与屏幕一致
 59                myMenuWidth=myMenu.getLayoutParams().width = screenWidth - myMenuPaddingRight;// 菜单的宽度=屏幕宽度-右边距
 60                myContent.getLayoutParams().width = screenWidth;// 内容宽度=屏幕宽度
 61                // 决定自身View的宽高,高与屏幕一致
 62                // 由于这里的LinearLayout里只包含了Menu和Content所以就不需要额外的去指定自身的宽
 63                once = true;
 64               }
 65           }
 66       
 67           /**
 68            * 
 69            * 设置MyHorizontalScrollView中的子组件View的位置,
 70            * 在初始时,先将Menu隐藏(在Myeclipse中ScrollView的画面内容(非滚动条)正数表示向左移,向上移)
 71            * 只显示内容界面
 72            */
 73         @Override
 74         protected void onLayout(boolean changed, int l, int t, int r, int b) {
 75             super.onLayout(changed, l, t, r, b);
 76             //刚载入界面的时候隐藏Menu菜单也就是ScrollView向左滑动菜单自身的大小
 77             if(changed){
 78                this.scrollTo(myMenuWidth, 0);//向左滑动,相当于把右边的内容页拖到正中央,菜单隐藏    
 79             }          
 80         }
 81         
 82         /**
 83          * 当手指在页面上滑动时,就会回调这个方法
 84          */
 85        @Override
 86        public boolean onTouchEvent(MotionEvent ev) {
 87                 int action=ev.getAction();
 88                 switch (action) {
 89                 case MotionEvent.ACTION_UP: //A pressed gesture has finished
 90                     int scrollX=this.getScrollX();//获得当前的滑动距离,非常明显,这个getScrollX()方法的返回值会随着滑动而动态的更新
 91                     if(scrollX>=myMenuWidth/2){ // 如果当前的滑动距离超过了Menu视图宽度的一半,那么就自动的显示整个内容视图
 92                         this.smoothScrollTo(myMenuWidth,0);//向左滑动展示内容
 93                     }else{ //否则就不自动滑动到内容视图
 94                         this.smoothScrollTo(0, 0);
 95                     }
 96                     return true;
 97                 }
 98                 return super.onTouchEvent(ev);
 99             }
100             
101        /**
102         * 
103         * 关于HorizontalScrollView的滑动,我们可以用onScrollChanged来监听参数L:
104         *打印日志:可以发现,当滚动条向左(画面向右滑动)的时候,L的值是逐渐增大的,
105         *所以我们可以通过它来作为动画的变化梯度值,也就是说,当手指在滑动时会回调这个方法
106         * 
107         */
108             
109          @Override
110          protected void onScrollChanged(int l, int t, int oldl, int oldt) {
111                 super.onScrollChanged(l, t, oldl, oldt);
112                 Log.i("tuzi",l+"");
113                 
114                 
115                 float scale = l * 1.0f / myMenuWidth; // 1 ~ 0
116                 float rightScale = 0.7f + 0.3f * scale;
117                 float leftScale = 1.0f - scale * 0.3f;
118                 float leftAlpha = 0.6f + 0.4f * (1 - scale);
119         
120                 // 调用属性动画,设置TranslationX
121                 ViewHelper.setTranslationX(myMenu, myMenuWidth * scale * 0.8f);                
122                 ViewHelper.setScaleX(myMenu, leftScale);
123                 ViewHelper.setScaleY(myMenu, leftScale);
124                 ViewHelper.setAlpha(myMenu, leftAlpha);
125                 // 设置内容缩放的中心点
126                 ViewHelper.setPivotX(myContent, 0);
127                 ViewHelper.setPivotY(myContent, myContent.getHeight() / 2);
128                 ViewHelper.setScaleX(myContent, rightScale);
129                 ViewHelper.setScaleY(myContent, rightScale);
130            }
131 }

出示一下文件资源列表

图片资源

posted @ 2014-11-25 20:26  RoperLee  阅读(346)  评论(0)    收藏  举报