前言:總有一天,你會成爲你想象的那樣。
轉載本文請註明出處,尊重原創:
如果想第一時間收到文章更新,可以微信掃描二維碼關注我的公衆號,或者微信直接搜索“Android小菜”進行關注,所有的文章會比CSDN更快一步:
覺得有幫助可以讚賞或者點個贊,都是對博主的支持。
本篇文章開始連續三篇會實現類似QQ測拉效果的自定義控件。分別使用不同的方式來實現同一效果。
本篇使用方式一來實現:HorizontalScrollView + LinearLayout + scrollTo + 屬性動畫。
說明:HorizontalScrollView 自動實現了滑動功能,裏面放置一個LinearLayout,LinearLayout橫向裏面放置兩個控件,左側菜單+主頁面佈局。
本文會從基本功能再到“特效”的步驟循序進行。
首先不加入動畫,先實現基本側滑功能,要實現的功能如下gif:
基礎功能由於很簡單,直接把代碼貼在下面:
public class QQSlidingMenu extends HorizontalScrollView {
/**
* 屏幕寬度
*/
private final int mScreenWidth;
/**
* 代表左側菜單和內部區域的父容器
*/
private LinearLayout mWapper;
/**
* 左側菜單區域
*/
private ViewGroup mLeftMenu;
/**
* 主頁面內容區域
*/
private ViewGroup mContentMenu;
/**
* 左側菜單完全展示距離右側的距離值dp
*/
private int mLeftMenuRightPadding = 50;
/**
* 左側菜單的寬度
*/
private int mLeftMenuWidth;
/**
* onMeasure只測量一次
*/
private boolean once;
public QQSlidingMenu(Context context, AttributeSet attrs) {
super(context, attrs);
//獲取屏幕寬度
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
mScreenWidth = metrics.widthPixels;
/**--------- dp--->px ---------**/
mLeftMenuRightPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,50,context.getResources().getDisplayMetrics());
}
/**
* 測量孩子的大小,確定自己的大小
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if(!once){
mWapper = (LinearLayout) this.getChildAt(0);
mLeftMenu = (ViewGroup) mWapper.getChildAt(0);
mContentMenu = (ViewGroup) mWapper.getChildAt(1);
//設置左右菜單的寬度
mLeftMenuWidth = mLeftMenu.getLayoutParams().width = mScreenWidth - mLeftMenuRightPadding;
mContentMenu.getLayoutParams().width = mScreenWidth;
once = true;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 擺放孩子控件的位置,確定自己的位置
* 通過設置偏移量讓左側菜單隱藏
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if(changed){
scrollTo(mLeftMenuWidth,0);
}
}
//滑動事件HorizontalScrollView已經幫忙給處理了,所以不需要down和move的操作
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:
// 判斷目前滑動到的位置,讓控件過度到某種狀態
// 如果左側菜單滑動超過了左側菜單的一半則展示左側菜單,如果滑動少於左側菜單一半則展示主頁面,隱藏左菜單
int scrollX = getScrollX();
if(scrollX >= mLeftMenuWidth/2){
smoothScrollTo(mLeftMenuWidth,0);
}else{
smoothScrollTo(0,0);
}
return true;
}
return super.onTouchEvent(ev);
}
}
沒錯,上面十幾行代碼就實現了最基本功能了。因爲HorizontalScrollView 已經具備了處理滑動事件的功能,我們只需要關心在哪個位置擡起手指(鼠標),以及讓控件平滑滑動到哪個位置。
然後對上面的代碼做個解析:
首先在構造方法裏面拿到屏幕的寬度,這個寬度待會要設置HorizontalScrollView孩子控件的寬度,接着是dp-->px的轉換,因爲要設置左側菜單控件距離屏幕右側的Padding值,這裏定義爲50dp。
然後重寫onMeasure方法,在裏面分別測量了自定義QQSlidingMenu控件的孩子控件的大小,因爲佈局文件中QQSlidingMenu的xml裏面是一個水平的LinearLayout控件,它裏面包含了兩個佈局,分別是左側菜單的佈局,和主頁內容的佈局。然後首先拿到LinearLayout實例,再根據getChildAt(i),分別拿到左側菜單和主頁內容的佈局實例,強轉爲ViewGroup類型。爲了方式多次測量,定義了一個標誌位,表示只需要測量一次。對於左側菜單的寬度=屏幕寬度-距離右側的padding值;對於主頁面的寬度就爲屏幕的寬度。
然後重寫onLayout方法,對孩子控件進行位置包房,由於默認情況下是下面擺放:
其中紫色區域是自定義的QQSlidingMenu。顯然默認是錯誤的,因此要改變控件的位置,看到只是簡單的一行代碼就設置了控件的初識位置。scrollTo到左側菜單的寬度,那麼測試的效果如下:
佈局擺放好了,往下就是滑動事件了,發現也很簡單,因爲咱們是繼承的HorizontalScrollView ,它已經默認做好了MOVE和DOWN事件了,所以只需要判斷一下UP事件就可以了。在UP的時候,判斷目前滑動到的位置,讓控件過度到某種狀態(是顯示菜單還是隱藏菜單);如果左側菜單往右滑動超過了左側菜單的一半則展示左側菜單,如果往右滑動少於左側菜單一半則展示主頁面,隱藏左菜單。並調用smoothScrollTo,讓佈局平滑過渡到某個值。然後說一下getScroll()這個值是多少,看下面一張圖:
灰色筆描述的就是getScroll()值,他表示控件相對屏幕劃過的距離,值大於0,表示控件是左滑得到的值,小於0,表示控件右滑得到的值。
上面屬於最基本的功能實現,我們考慮,在控件的代碼中,我按照自己的意願寫了50dp的padding值,那麼別人如果想設置爲100dp,或者150dp怎麼辦,難道要修改代碼嗎?所以,有必要加入自定義屬性,通過這種方式在xml中,手動設置padding,而不是去修改代碼:
新建一個名稱爲attr的xml文件:
然後在這裏面做一點文章:
上面是定義了一個屬性,待會再xml佈局中我們就要使用該自定義的屬性。
在QQSlidingMenu控件的構造方法中加入如下代碼:
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.QQSlidingMenu);
int count = array.getIndexCount();
for (int i = 0; i < count; i++) {
int attr = array.getIndex(i);
switch (attr) {
case R.styleable.QQSlidingMenu_mRightPadding:
mLeftMenuRightPadding = array.getDimensionPixelSize(attr,
(int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,50,
context.getResources().getDisplayMetrics()));
break;
default:
break;
}
}
array.recycle();
然後在佈局文件中引入自定義屬性:
我們自定義屬性的方式,設置padding值爲100dp,那麼此時運行後,左側菜單距離屏幕右側的寬度肯定是會增加的。
此時運行程序看一下側滑菜單展示的樣式:
以上加上了自定義屬性,緊接着,我們加上一個menu按鈕,來實現點擊按鈕打開左側菜單的功能:
在自定義QQSlidingMenu裏面,加入如下打開和關閉的代碼,並且提供一個共有的toogle方法:
當然,在滑動的時候,也要修改一下標誌位:
再運行程序:
以上是本篇所講內容,下一篇會修改這裏的代碼,加入一些動畫,實現抽屜效果,
想第一時間查看文章,請關注公衆號:“Android小菜”。