1、繼承HorizontalScrollerView(水平滾動條),好處:無需判斷高度只需考慮水平寬度,可以省去MOVE衝突的處理。
2、菜單佈局文件left_menu.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/img_frame_background"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/img_1"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="20sp"
android:text="第一個文本" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/img_2"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="20sp"
android:text="第二個文本" />
</LinearLayout>
</RelativeLayout>
mainActivity.xml文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:dan="http://schemas.android.com/apk/res/com.example.recycleview"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.recycleview.view.SlidingMenu
android:id="@+id/id_menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
dan:rightPadding="100dp" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal" >
<include layout="@layout/left_menu" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/qq" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="toggleMenu"
android:text="切換菜單" />
</LinearLayout>
</LinearLayout>
</com.example.recycleview.view.SlidingMenu>
</RelativeLayout>
3、自定義View:SlidingMenu.java,繼承水平滾動控件類
1、首先實現其兩個參數的構造方法
2、將自定義的HorizontalScrollView名字改成自定義的屬性名 包名+類名
…………………………
>
3、自定義ViewGroup:
(1)、onMeasure:決定內部View(子View)的寬和高以及自己的寬和高
(2)、onLayout:決定子View放置的位置
(3)、onTouchEvent:判斷用戶的手指狀態
public class SlidingMenu extends HorizontalScrollView {
private LinearLayout mWapper;
private ViewGroup mMenu;
private ViewGroup mContent;
private int mScreenWidth;
private int mMenuRightPadding = 50;// menu與屏幕右側的距離dp
private int mMenuWidth;
private boolean once;// onMeasure會調用多次,設置一個boolean值
private boolean isOpen; //默認打開時爲false
float scale;
/*
* 沒有使用自定義屬性時,調用這個參數
*/
public SlidingMenu(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
/*
* 自定義ViewGroup 1、onMeasure 決定內部view的寬和高 2、onLayout 決定子view的放置的位置
* 3、onTouchEvent 判斷用戶的手指狀態
*/
/*
* 當使用了自定義屬性時,會調用此構造方法
*/
public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 獲取我們定義的屬性
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.SlidingMenu, defStyle, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.SlidingMenu_rightPadding:
mMenuRightPadding = a.getDimensionPixelSize(attr,
(int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 50, context
.getResources().getDisplayMetrics()));// attr是新賦值,第二個是默認值
break;
}
}
a.recycle();// 釋放掉
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);// 寬高被賦值了
mScreenWidth = outMetrics.widthPixels;
}
public SlidingMenu(Context context) {
this(context, null);
// TODO Auto-generated constructor stub
}
// 設置子view的寬和高,設置自己的寬和高
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!once) {
mWapper = (LinearLayout) getChildAt(0);
mMenu = (ViewGroup) mWapper.getChildAt(0);// LinearLayout第一個元素
mContent = (ViewGroup) mWapper.getChildAt(1);// LinearLayout第二個元素
mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth
- mMenuRightPadding;
mContent.getLayoutParams().width = mScreenWidth;
once = true;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
// 通過設置偏移量,將menu隱藏
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed) {
this.scrollTo(mMenuWidth, 0);// scrollTo是隱藏的方法,瞬間完成的動作
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {// 默認自動能把隱藏的滑出來,所以關心Action_UP
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_UP:
int scrollX = getScrollX();// scrollX隱藏在左邊的寬度
if (scrollX >= mMenuWidth / 2) {
this.smoothScrollTo(mMenuWidth, 0);// smoothScrollTo是動畫隱藏的方法
isOpen=false;
} else {
this.smoothScrollTo(0, 0);//打開menu
isOpen=true;
}
return true;
}
return super.onTouchEvent(ev);
}
// 打開菜單
public void openMenu(){
if (isOpen) return;
this.smoothScrollTo(0, 0);
isOpen=true;
}
public void closeMenu(){
if (!isOpen) return;
this.smoothScrollTo(mMenuWidth, 0);
isOpen=false;
}
//切換菜單
public void toggle(){
if(isOpen){
closeMenu();
}else {
openMenu();
}
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
scale=l*1.0f/mMenuWidth;//1~0
//調用屬性動畫,設置TranslationX mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth- mMenuRightPadding;
float rightScale=0.7f+0.3f*scale;
float leftScale=1.0f-scale*0.3f;
float leftAlpha=0.6f+0.4f*(1-scale);
ViewHelper.setTranslationX(mMenu, mMenuWidth*scale*0.8f);
ViewHelper.setScaleX(mMenu, leftScale);
ViewHelper.setScaleY(mMenu,leftScale );
ViewHelper.setAlpha(mMenu, leftAlpha);
// mContent的縮放及焦點
ViewHelper.setScaleX(mContent,rightScale);
ViewHelper.setScaleY(mContent,rightScale);
ViewHelper.setPivotX(mContent, 0);
ViewHelper.setPivotY(mContent, mContent.getHeight()/2);
}
}
4、、用戶自定義屬性
至此,側滑已經實現。接下來加入自定義屬性,可以讓用戶去設置菜單離屏幕右邊的邊距。
(1)、在values文件夾中創建一個xml文件,叫做attr.xml
(2)注意:在xml文件中編寫自定義屬性時是沒有代碼提示功能的,因此要注意代碼拼寫
(3)接下來要在mainActivity.xml文件中命名空間進行聲明:
xmlns:dan=”http://schemas.android.com/apk/res/com.example.recycleview”
注意:這裏的格式是xmlns:自己編寫,可以是任何名字=”http://schemas.android.com/apk/res/當前應用的包名,而不是View的包名”
(4)、接下來將自定義屬性放到View中進行使用
Alan:rightPadding=”100dp”
(5)、在剛纔未使用自定義屬性時,調用自身的構造方法,定義之後,需要生成另外兩個構造方法:將原來兩個參數構造方法中的方法拷貝到三個參數的構造方法之中,然後將兩個參數構造方法的第三個參數設置爲0,將一個參數的構造方法(傳入上下文對象方法)的第二個參數設置爲null,即調用兩個參數的構造方法。
(6)、獲取我們定義的屬性:在三個參數的構造方法中獲取:通過TypedArray這個類獲得自定義屬性,這裏需要注意的是TypedArray這個類用完之後需要進行釋放(recycled)。
5、attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="rightPadding" format="dimension"></attr>
<declare-styleable name="SlidingMenu">
<attr name="rightPadding"></attr>
</declare-styleable>
</resources>
6、下面是MainActivity的實現
public class MainActivity extends Activity {
private SlidingMenu mLeftMenu;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
mLeftMenu=(SlidingMenu) findViewById(R.id.id_menu);
}
public void toggleMenu(View v){
mLeftMenu.toggle();
}
}