天天看點

自定義進階控件打造主流的側滑菜單控件

今天咱們來實作一個側滑效果,簡單而又輕巧。大家下載下傳源碼,直接參照源碼,使用非常簡單。我就不上傳github,如果大家有需要的話,請在下面留言,給大家打包成類庫。

大家知道側滑菜單非常流行,包括現在的QQ側滑菜單,酷狗的縮放動畫的側滑菜單,都是非常棒的。這個側滑控件還是能滿足大多數實際項目需求的。如果說簡單而又有内涵,是不是霸氣呢?我們現在就開始學習如何去自己寫一個。效果圖如下。

自定義進階控件打造主流的側滑菜單控件

先帶大家了解一下題外内容。大家知道什麼是子節點,父節點嗎?知道的話,本段可以略過了。其實這個說一下,是為了後面做鋪墊的。在DDMS工具中,有個工具叫做Hierarchy。

,這個工具在哪呢?其實就在我們的DDMS界面。

自定義進階控件打造主流的側滑菜單控件
自定義進階控件打造主流的側滑菜單控件

大家看右圖的右側,就是這個界面的布局節點。節點的英文單詞叫做node。

ok,了解了上面的内容之後,咱們就可以正式開始我們的側滑項目了。

我們要實作側滑,那麼我們該繼承哪個類呢?其實大家可以從View繼承,不過太麻煩了。那麼我們可以繼承一個已經實作了滾動的控件HorizontalScrollView。

我們先來看下側滑的實質是什麼樣的,請允許我自畫一個略顯醜陋的圖吧。

自定義進階控件打造主流的側滑菜單控件

最外層其實就是一個HorizontalScrollView,裡面包含了Menu布局界面和主界面。

第一步:先寫一個類繼承自HorizontalScrollView。

注意:實作第二個帶有2個參數的構造方法,為什麼實作第二個呢?當我們不需要定義新的屬性的時候,我們隻需要實作帶有2個參數的構造方法。

public class SlidingMenu extends HorizontalScrollView{
public SlidingMenu(Context context, AttributeSet attrs) {
	super(context, attrs);
	}
}
           

第二步:編寫main.xml(主界面),menu.xml(菜單頁),以及HorizontalScrollView自身的布局界面

main.xml就是一個圖檔,具體的大家根據項目實際寫。menu菜單代碼如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="match_parent" 
    android:orientation="vertical"
    android:background="@drawable/background">
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginTop="50dp"
        android:layout_marginLeft="50dp"
        >
        <ImageView 
            android:layout_width="45dp"
            android:layout_height="45dp"
            android:src="@drawable/weibo"
            />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginLeft="10dp"
            android:gravity="center"
            android:text="menu1"
            android:textSize="20sp" />
    </LinearLayout>
<!--此處省略三個item,和上面的那個LinearLayout内容相似,大家可以把文字和圖檔替換掉就可以了-->
           

</LinearLayout>

随後,我們可以把這兩個界面插入到HorizontalScrollView自身的布局中去,也就是我們項目自動生成的activity_main.xml布局。

<com.example.slidingmenu.widget.SlidingMenu
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:scrollbars="none"
    android:fadingEdge="none"
    >
    <!--上面的最後2行是為了去除滾動條和陰影效果-->
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:orientation="horizontal" >

        <include layout="@layout/menu"/>
        <LinearLayout 
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="@drawable/main"
            ></LinearLayout>
    </LinearLayout>
</com.example.slidingmenu.widget.SlidingMenu>
           
自定義進階控件打造主流的側滑菜單控件

大家注意了,menu菜單僅僅是左邊的,還有部分顯示的是主界面的。這個在後面的代碼裡會實作。

第三步:完善SlidingMenu類,首先得到螢幕寬度

我們首先得到螢幕的寬度。為了後面的計算Menu菜單和主界面布局寬度作為鋪墊。

public class SlidingMenu extends HorizontalScrollView{
	
	private ViewGroup mMenuLayout;//菜單布局界面
	private ViewGroup mMainLayout;//主布局界面
	private int mScreenWidth;//螢幕寬度
	private int mPaddingRight = 100;//右邊距大小
	private float downX;//按下時候的橫坐标
	private float upX;//手指松開時候的橫坐标
	private int mMenuWidth;//菜單界面寬度
	/**
	 * @param context
	 * @param attrs
	 */
	public SlidingMenu(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		Display display = wm.getDefaultDisplay();
		DisplayMetrics displayMetrics = new DisplayMetrics();
		display.getMetrics(displayMetrics);
		mScreenWidth = displayMetrics.widthPixels;
	}
}
           

在拿到了螢幕的寬度之後,我們就可以來計算menu菜單界面和主界面分别在螢幕中的寬度了。

我們很容易想到,總的寬度就是menu菜單加上主界面的寬度。我們可以清楚地看到menu菜單的寬度有個padding邊距。這個右邊距我設定的是100。感覺還可以。

     menu菜單頁寬度 = 螢幕寬度 - 右邊距

主界面寬度 = 螢幕寬度

上面式子大家應該看懂了吧!看懂了就好辦。

第四步:計算munu菜單和主界面菜單寬度。重寫onMeasure方法

@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		LinearLayout layout = (LinearLayout)getChildAt(0);//得到最外層的LinearLayout布局檔案
		//菜單布局
		mMenuLayout = (ViewGroup) layout.getChildAt(0);
		//主界面布局
		mMainLayout = layout.getChildAt(1);
		mMenuWidth = mScreenWidth - mPaddingRight;//菜單寬度
		//設定菜單寬度
		mMenuLayout.getLayoutParams().width = mMenuWidth;
		//主布局寬度
		mMainLayout.getLayoutParams().width = mScreenWidth;
	}
           

getChildAt(int index)這個方法可以得到子節點,這裡我們先得到父LinearLayout布局,再根據getChildAt方法得到子view的布局。

可能大家會問,為什麼要這樣得到2個view呢,其實ViewGroup是view的子類。通過上面的DDMS中的樹形圖可以很好的明白。我們可以知道這2個LinearLayout是同一級别的,都是在父LinearLayout節點的下面。

這樣我們就實作了上圖的效果,可實際上效果是這樣嗎?不好意思,到這裡,我們雖然可以滑動,但是滑動起來可能不流暢。

怎麼辦呢?

這個時候,我們需要實作手勢動作的監聽。

當我們向右邊滑動的時候,主布局要隐藏大半部分,隻留下了右邊距寬度的可視,其他的都在不可視範圍内。并不代表消失。

@Override
	public boolean onTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			downX = ev.getX();//按下的橫坐标
			break;

		case MotionEvent.ACTION_UP:
			upX = ev.getX();//松開的橫坐标
			float d = upX - downX;
			if(d<0){
				//往左移動
				this.smoothScrollTo(mMenuWidth, 0);
			}else{
				//向右滑動
				this.smoothScrollTo(0, 0);
			}
			return true;
		default:
				break;
		}
		return super.onTouchEvent(ev);
	}
           

第四步:初始化布局

最後,我們需要初始化渲染布局位置。請注意了,初始化的時候我們的menu菜單完全隐藏,隻留下主界面布局可視。是以我們需要重寫onLayout方法。

/*
	 * (non-Javadoc)
	 * @see android.widget.HorizontalScrollView#onLayout(boolean, int, int, int, int)
	 */
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		this.smoothScrollTo(mMenuWidth, 0);//初始化布局界面
	}
           

看到這裡,相信大家都已經學會了如何實作側滑了。大家覺得有問題的話可以留言哦!下篇會對SlidingMenu進行縮放動畫擴充及更精确地判斷監聽手勢。敬請期待!

源碼下載下傳