iOS及Android上的瑞士军刀界面很是新颖,也很便捷。很多应用采用了该设计,例如QQ,凤凰新闻客户端等。今天介绍一下通过自定义HorizontalScrollView类的方法实现瑞士军刀界面。
依赖jar包
NineOldAndroids.jar
思路
●使用HorizontalScrollView布局,左侧为Menu,右侧为Content;
自定义HorizontalScrollView,使之监听Action_UP事件,进行Menu的显示和隐藏;
●menu隐藏在抽屉正下方
属性动画:改变拖动时,
调用动画时机:ACTION_MOVE==>覆写View类的onScrollChanged()方法
●菜单及内容区域的缩放和透明度变化
拖动时 scale:1.0-0
menu透明度变化:0.7-1.0
menu缩放变化:0.7-1.0
content缩放变化:1.0-0.7【注意默认缩放中心会影响实际效果,需要设置缩放中心】
效果图
核心代码
自定义HorizontalScrollView类SlidingMenu
public class SlidingMenu extends HorizontalScrollView {
private LinearLayout mWrapper;
private ViewGroup mMenu;
private ViewGroup mContent;
private int menuWidth;
private int slidingMenuPadding;
private int screenWidth;
private boolean once;
private boolean isOpen;
public SlidingMenu(Context context, AttributeSet attr) {
super(context, attr);
DisplayMetrics dm = new DisplayMetrics();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics(dm);
screenWidth = dm.widthPixels;
slidingMenuPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 80,
context.getResources().getDisplayMetrics());
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
this.scrollTo(menuWidth, 0);
super.onLayout(changed, l, t, r, b);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!once) {
mWrapper = (LinearLayout) getChildAt(0);
mMenu = (ViewGroup) mWrapper.getChildAt(0);
mContent = (ViewGroup) mWrapper.getChildAt(1);
menuWidth = mMenu.getLayoutParams().width = screenWidth - slidingMenuPadding;
mContent.getLayoutParams().width = screenWidth;
once = true;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_UP:
int scrollX = getScrollX();
if (scrollX >= menuWidth / 2) {
this.smoothScrollTo(menuWidth, 0);
isOpen = false;
} else {
this.smoothScrollTo(0, 0);
isOpen = true;
}
return true;
}
return super.onTouchEvent(ev);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
float scale = l * 1.0f / menuWidth;
float rightScale = 0.7f + scale * 0.3f;
float leftScale = 1.0f - scale * 0.3f;
float leftAlpha = 1.0f - scale * 0.3f;
ViewHelper.setTranslationX(mMenu, l * 0.5f);
ViewHelper.setScaleX(mMenu, leftScale);
ViewHelper.setScaleY(mMenu, leftScale);
ViewHelper.setAlpha(mMenu, leftAlpha);
ViewHelper.setPivotX(mContent, 0);
ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);
ViewHelper.setScaleX(mContent, rightScale);
ViewHelper.setScaleY(mContent, rightScale);
}
public void trigger() {
if (isOpen) {
closeMenu();
isOpen = false;
} else {
openMenu();
isOpen = true;
}
}
private void openMenu() {
if (isOpen) return;
this.smoothScrollTo(0, 0);
}
private void closeMenu() {
if (!isOpen) return;
this.smoothScrollTo(menuWidth, 0);
}
}
布局
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/leaf" >
<com.example.dialogtest.SlidingMenu
android:id="@+id/menu_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal" >
<include layout="@layout/sliding_menu" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/apple" >
<Button
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:background="@drawable/title_bar_menu"
android:onClick="showMenu" />
</LinearLayout>
</LinearLayout>
</com.example.dialogtest.SlidingMenu>
</RelativeLayout>