安卓開發筆記——自定義HorizontalScrollView控件(實現QQ5.0側滑效果)


對於滑動菜單欄SlidingMenu,大家應該都不陌生,在市場上的一些APP應用里經常可以見到,比如人人網,FaceBook等。

前段時間QQ5.0版本出來后也采用了這種設計風格:(下面是效果圖)

之前在GitHub上看到過關於此設計風格的開源項目,它只需要引入對應的類庫,就可以定制靈活、各種陰影和漸變以及動畫的滑動效果的側滑菜單。

這里是關於開源組件的介紹網址:https://github.com/jfeinstein10/SlidingMenu

但作為開發人員,在學習階段還是建議盡可能的去自己實現,所以今天我不講此開源項目的使用方式,我們用自定義HorizontalScrollView來實現此效果。

下面先看下實現效果圖:

     

 上圖的效果是用自定義HorizontalScrollView來實現的,在HorizontalScrollView里潛入一個橫向排列的線性布局,然后在線性布局里分別加入菜單布局和內容布局,在我們初始化的時候把HorizontalScrollView的滾動條向左拉至左邊菜單距離即可實現菜單布局的隱藏,關於縮放,移動效果我們可以使用開源動畫庫nineoldandroids來實現,只需要幾行代碼。

 

好了,接着直接上代碼吧:

首先,先看下布局文件:

 

1、菜單欄布局文件:

  1 <?xml version="1.0" encoding="utf-8"?>
  2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  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             android:layout_centerInParent="true" >
 15 
 16             <ImageView
 17                 android:id="@+id/menuimage1"
 18                 android:layout_width="50dp"
 19                 android:layout_height="50dp"
 20                 android:layout_centerVertical="true"
 21                 android:layout_marginLeft="20dp"
 22                 android:layout_marginTop="20dp"
 23                 android:src="@drawable/img_1" />
 24 
 25             <TextView
 26                 android:id="@+id/menutext1"
 27                 android:layout_width="wrap_content"
 28                 android:layout_height="wrap_content"
 29                 android:layout_centerVertical="true"
 30                 android:layout_marginLeft="20dp"
 31                 android:layout_marginTop="20dp"
 32                 android:layout_toRightOf="@id/menuimage1"
 33                 android:text="菜單一"
 34                 android:textColor="@android:color/white"
 35                 android:textSize="20dp" />
 36         </RelativeLayout>
 37         
 38         
 39                 <RelativeLayout
 40             android:layout_width="match_parent"
 41             android:layout_height="wrap_content"
 42             android:layout_centerInParent="true" >
 43 
 44             <ImageView
 45                 android:id="@+id/menuimage2"
 46                 android:layout_width="50dp"
 47                 android:layout_height="50dp"
 48                 android:layout_centerVertical="true"
 49                 android:layout_marginLeft="20dp"
 50                 android:layout_marginTop="20dp"
 51                 android:src="@drawable/img_2" />
 52 
 53             <TextView
 54                 android:id="@+id/menutext2"
 55                 android:layout_width="wrap_content"
 56                 android:layout_height="wrap_content"
 57                 android:layout_centerVertical="true"
 58                 android:layout_marginLeft="20dp"
 59                 android:layout_marginTop="20dp"
 60                 android:layout_toRightOf="@id/menuimage2"
 61                 android:text="菜單二"
 62                 android:textColor="@android:color/white"
 63                 android:textSize="20dp" />
 64         </RelativeLayout>
 65         
 66                         <RelativeLayout
 67             android:layout_width="match_parent"
 68             android:layout_height="wrap_content"
 69             android:layout_centerInParent="true" >
 70 
 71             <ImageView
 72                 android:id="@+id/menuimage3"
 73                 android:layout_width="50dp"
 74                 android:layout_height="50dp"
 75                 android:layout_centerVertical="true"
 76                 android:layout_marginLeft="20dp"
 77                 android:layout_marginTop="20dp"
 78                 android:src="@drawable/img_3" />
 79 
 80             <TextView
 81                 android:id="@+id/menutext3"
 82                 android:layout_width="wrap_content"
 83                 android:layout_height="wrap_content"
 84                 android:layout_centerVertical="true"
 85                 android:layout_marginLeft="20dp"
 86                 android:layout_marginTop="20dp"
 87                 android:layout_toRightOf="@id/menuimage3"
 88                 android:text="菜單三"
 89                 android:textColor="@android:color/white"
 90                 android:textSize="20dp" />
 91         </RelativeLayout>
 92         
 93                         
 94                                 <RelativeLayout
 95             android:layout_width="match_parent"
 96             android:layout_height="wrap_content"
 97             android:layout_centerInParent="true" >
 98 
 99             <ImageView
100                 android:id="@+id/menuimage4"
101                 android:layout_width="50dp"
102                 android:layout_height="50dp"
103                 android:layout_centerVertical="true"
104                 android:layout_marginLeft="20dp"
105                 android:layout_marginTop="20dp"
106                 android:src="@drawable/img_4" />
107 
108             <TextView
109                 android:id="@+id/menutext4"
110                 android:layout_width="wrap_content"
111                 android:layout_height="wrap_content"
112                 android:layout_centerVertical="true"
113                 android:layout_marginLeft="20dp"
114                 android:layout_marginTop="20dp"
115                 android:layout_toRightOf="@id/menuimage4"
116                 android:text="菜單四"
117                 android:textColor="@android:color/white"
118                 android:textSize="20dp" />
119         </RelativeLayout>
120         
121                                 
122                                         <RelativeLayout
123             android:layout_width="match_parent"
124             android:layout_height="wrap_content"
125             android:layout_centerInParent="true" >
126 
127             <ImageView
128                 android:id="@+id/menuimage5"
129                 android:layout_width="50dp"
130                 android:layout_height="50dp"
131                 android:layout_centerVertical="true"
132                 android:layout_marginLeft="20dp"
133                 android:layout_marginTop="20dp"
134                 android:src="@drawable/img_5" />
135 
136             <TextView
137                 android:id="@+id/menutext5"
138                 android:layout_width="wrap_content"
139                 android:layout_height="wrap_content"
140                 android:layout_centerVertical="true"
141                 android:layout_marginLeft="20dp"
142                 android:layout_marginTop="20dp"
143                 android:layout_toRightOf="@id/menuimage5"
144                 android:text="菜單五"
145                 android:textColor="@android:color/white"
146                 android:textSize="20dp" />
147         </RelativeLayout>
148     </LinearLayout>
149 
150 </RelativeLayout>

2、主內容布局文件:

 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.example.sidesliptest.MyHorizontalScrollView 
 8     android:layout_height="match_parent"
 9     android:layout_width="match_parent"
10     android:scrollbars="none"
11     >
12     <LinearLayout 
13         android:layout_height="match_parent"
14         android:layout_width="match_parent"
15         android:orientation="horizontal"
16         >
17         <include layout="@layout/left_menu"/>
18         <LinearLayout 
19             android:layout_width="match_parent"
20             android:layout_height="match_parent"
21             android:background="@drawable/qq"
22             ></LinearLayout>
23         
24     </LinearLayout>
25     
26 </com.example.sidesliptest.MyHorizontalScrollView>
27 
28 </RelativeLayout>

 

3、自定義View(HorizontalScrollView)類:

自定義Viewi實現步驟:

1、繼承要自定義View的類,並實現帶有參數的構造方法

2、重寫onMeasure(確定自定義View的大小)和onLayout(確定自定義View的位置)方法

 

關於HorizontalScrollView的滑動,我們可以用onScrollChanged來監聽參數L:

打印日志:可以發現,當滾動條向左(畫面向右滑動)的時候,L的值是逐漸增大的,所以我們可以通過它來作為動畫的變化梯度值。

注釋很全,具體看注釋吧。

  1 package com.example.sidesliptest;
  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 
 14 import com.nineoldandroids.view.ViewHelper;
 15 
 16 public class MyHorizontalScrollView extends HorizontalScrollView {
 17 
 18     // 在HorizontalScrollView有個LinearLayout
 19     private LinearLayout linearLayout;
 20     // 菜單,內容頁
 21     private ViewGroup myMenu;
 22     private ViewGroup myContent;
 23     //菜單寬度
 24     private int myMenuWidth;
 25 
 26     // 屏幕寬度
 27     private int screenWidth;
 28     // 菜單與屏幕右側的距離(dp)
 29     private int myMenuPaddingRight = 50;
 30 
 31     // 避免多次調用onMeasure的標志
 32     private boolean once = false;
 33 
 34     /**
 35      * 自定義View需要實現帶有Context、AttributeSet這2個參數的構造方法,否則自定義參數會出錯
 36      * 當使用了自定義屬性時,會調用此構造方法
 37      * 
 38      * @param context
 39      * @param attrs
 40      */
 41     public MyHorizontalScrollView(Context context, AttributeSet attrs) {
 42         super(context, attrs);
 43         // 獲取屏幕寬度
 44         WindowManager windowManager = (WindowManager) context
 45                 .getSystemService(Context.WINDOW_SERVICE);
 46         DisplayMetrics outMetrics = new DisplayMetrics();
 47         windowManager.getDefaultDisplay().getMetrics(outMetrics);
 48         screenWidth = outMetrics.widthPixels;// 屏幕寬度
 49 
 50         // 將dp轉換px
 51         myMenuPaddingRight = (int) TypedValue.applyDimension(
 52                 TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources()
 53                         .getDisplayMetrics());
 54 
 55     }
 56 
 57     /**
 58      * 設置子View的寬高,決定自身View的寬高,每次啟動都會調用此方法
 59      */
 60     @Override
 61     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 62         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 63         if (!once) {//使其只調用一次
 64             // this指的是HorizontalScrollView,獲取各個元素
 65             linearLayout = (LinearLayout) this.getChildAt(0);// 第一個子元素
 66             myMenu = (ViewGroup) linearLayout.getChildAt(0);// HorizontalScrollView下LinearLayout的第一個子元素
 67             myContent = (ViewGroup) linearLayout.getChildAt(1);// HorizontalScrollView下LinearLayout的第二個子元素
 68 
 69             // 設置子View的寬高,高於屏幕一致
 70             myMenuWidth=myMenu.getLayoutParams().width = screenWidth - myMenuPaddingRight;// 菜單的寬度=屏幕寬度-右邊距
 71             myContent.getLayoutParams().width = screenWidth;// 內容寬度=屏幕寬度
 72             // 決定自身View的寬高,高於屏幕一致
 73             // 由於這里的LinearLayout里只包含了Menu和Content所以就不需要額外的去指定自身的寬
 74             once = true;
 75         }
 76     }
 77 
 78     //設置View的位置,首先,先將Menu隱藏(在eclipse中ScrollView的畫面內容(非滾動條)正數表示向左移,向上移)
 79     @Override
 80     protected void onLayout(boolean changed, int l, int t, int r, int b) {
 81         super.onLayout(changed, l, t, r, b);
 82         //剛載入界面的時候隱藏Menu菜單也就是ScrollView向左滑動菜單自身的大小
 83         if(changed){
 84             this.scrollTo(myMenuWidth, 0);//向左滑動,相當於把右邊的內容頁拖到正中央,菜單隱藏    
 85         }
 86     
 87     }
 88     
 89     @Override
 90     public boolean onTouchEvent(MotionEvent ev) {
 91         int action=ev.getAction();
 92         switch (action) {
 93         case MotionEvent.ACTION_UP:
 94             int scrollX=this.getScrollX();//滑動的距離scrollTo方法里,也就是onMeasure方法里的向左滑動那部分
 95             if(scrollX>=myMenuWidth/2){
 96                 this.smoothScrollTo(myMenuWidth,0);//向左滑動展示內容
 97             }else{
 98                 this.smoothScrollTo(0, 0);
 99             }
100             return true;
101         }
102         return super.onTouchEvent(ev);
103     }
104     
105     
106     @Override
107     protected void onScrollChanged(int l, int t, int oldl, int oldt) {
108         super.onScrollChanged(l, t, oldl, oldt);
109         Log.i("tuzi",l+"");
110         float scale = l * 1.0f / myMenuWidth; // 1 ~ 0
111      
121         float rightScale = 0.7f + 0.3f * scale;
122         float leftScale = 1.0f - scale * 0.3f;
123         float leftAlpha = 0.6f + 0.4f * (1 - scale);
124 
125         // 調用屬性動畫,設置TranslationX
126         ViewHelper.setTranslationX(myMenu, myMenuWidth * scale * 0.8f);
127         
128         ViewHelper.setScaleX(myMenu, leftScale);
129         ViewHelper.setScaleY(myMenu, leftScale);
130         ViewHelper.setAlpha(myMenu, leftAlpha);
131         // 設置內容縮放的中心點
132         ViewHelper.setPivotX(myContent, 0);
133         ViewHelper.setPivotY(myContent, myContent.getHeight() / 2);
134         ViewHelper.setScaleX(myContent, rightScale);
135         ViewHelper.setScaleY(myContent, rightScale);
136     }
137 
138 } 

4、主程序類:

package com.example.sidesliptest;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
    }


}

 

圖片素材:http://pan.baidu.com/s/1kTkjmAj

 

 

作者:Balla_兔子
出處:http://www.cnblogs.com/lichenwei/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
正在看本人博客的這位童鞋,我看你氣度不凡,談吐間隱隱有王者之氣,日后必有一番作為!旁邊有“推薦”二字,你就順手把它點了吧,相得准,我分文不收;相不准,你也好回來找我!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM