AndroidはQQのサイドバーに似ています
14065 ワード
まず効果図を見てみましょう.
メインインタフェースのqqインタフェースは私が切り取った図です.実際にレイアウトを描いたわけではありません.スライドしたメニューは手書きのレイアウトです.
全体的な考え方:全体はHorizontalScrollViewです.スライドの距離がスクリーンの3分の1より大きい場合.サイドバーを展開します.さもないとまた滑って帰ります.
レイアウトを見てみましょう.
カスタムコントロールの完全なコードは次のとおりです.
このコードから,メインインタフェースの設定は画面の幅,サイドバーの幅は自己幅から100 dp減算されることがわかる.これによりサイドバーの右側が100 dpカットされます.
2初期化時に、このカスタムコントロールをメインインタフェースに表示される位置にスライドさせます.
3サイドバーをスライドするとき、スライドの幅を計算します.
4スライド中にサイドバーの透明度とサイズと移動効果を変更するカスタムコントロールは、スライド中にonScrolchangedメソッドを複数回コールバックします.
右に移動するとこの隙間はありません.
メインインタフェースのqqインタフェースは私が切り取った図です.実際にレイアウトを描いたわけではありません.スライドしたメニューは手書きのレイアウトです.
全体的な考え方:全体はHorizontalScrollViewです.スライドの距離がスクリーンの3分の1より大きい場合.サイドバーを展開します.さもないとまた滑って帰ります.
レイアウトを見てみましょう.
<com.yeliang.sliding_menu.SlidingMenu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<include layout="@layout/menu">include>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/qq">LinearLayout>
LinearLayout>
com.yeliang.sliding_menu.SlidingMenu>
最外層は、HorizontalScrollViewから継承されたカスタムコントロールです.何も言うことはない.私のメインインタフェースがqqのメインインタフェースのスクリーンショットであることがわかります.スライドメニューのレイアウトを導入しました.カスタムコントロールの完全なコードは次のとおりです.
public class SlidingMenu extends HorizontalScrollView {
//
private int mScreenWidth;
//
private ViewGroup mMenu;
//
private ViewGroup mMain;
private int mMenuRightPadding = 100;
private int mMenuWidth;
private boolean isInit = true;
public SlidingMenu(Context context, AttributeSet attrs) {
super(context, attrs);
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
setHorizontalScrollBarEnabled(false);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (isInit) {
LinearLayout wrapper = (LinearLayout) getChildAt(0);
mMenu = (ViewGroup) wrapper.getChildAt(0);
mMain = (ViewGroup) wrapper.getChildAt(1);
mMenuWidth = mScreenWidth - mMenuRightPadding;
mMenu.getLayoutParams().width = mMenuWidth;
mMain.getLayoutParams().width = mScreenWidth;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed) {
isInit = false;
}
scrollTo(mMenuWidth, 0);
super.onLayout(changed, l, t, r, b);
}
private float downX;
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
downX = ev.getX();
break;
case MotionEvent.ACTION_UP:
//
float dx = ev.getX() - downX;
// 1/3
if (dx < mScreenWidth / 3) {
smoothScrollTo(mMenuWidth, 0);
} else {
smoothScrollTo(0, 0);
}
return true;
default:
break;
}
return super.onTouchEvent(ev);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
//
float factor = (float) l / mMenuWidth;
//
mMenu.setTranslationX(mMenuWidth * factor * 0.6f);
//
float menuScale = 1 - 0.4f * factor;
mMenu.setScaleX(menuScale);
mMenu.setScaleY(menuScale);
//
mMenu.setAlpha(1 - factor);
}
}
1まず、メインインタフェースとサイドバーの幅を決定します.構築方法での画面幅の取得WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
スクロールバーの削除setHorizontalScrollBarEnabled(false);
次に、onMeasure()メソッドでは、画面の幅に応じて、サイドバーとメインインタフェースの幅に値を割り当てます. if (isInit) {
LinearLayout wrapper = (LinearLayout) getChildAt(0);
mMenu = (ViewGroup) wrapper.getChildAt(0);
mMain = (ViewGroup) wrapper.getChildAt(1);
mMenuWidth = mScreenWidth - mMenuRightPadding;
mMenu.getLayoutParams().width = mMenuWidth;
mMain.getLayoutParams().width = mScreenWidth;
}
onMeasure()は複数回呼び出されるためです.だからここはisInitでマークしました.そしてonLayout()実行後にisInitをfalseに設定します.これにより、この割り当てられたコードは繰り返し実行されません.このコードから,メインインタフェースの設定は画面の幅,サイドバーの幅は自己幅から100 dp減算されることがわかる.これによりサイドバーの右側が100 dpカットされます.
2初期化時に、このカスタムコントロールをメインインタフェースに表示される位置にスライドさせます.
if (changed) {
isInit = false;
}
scrollTo(mMenuWidth, 0);
カスタムコントロール全体の幅は、サイドバーの幅とメインインタフェースの幅です.したがって、このカスタムコントロールを初期化するときにメインインタフェースを表示するには、サイドバーの幅を左にスライドさせる必要があります.3サイドバーをスライドするとき、スライドの幅を計算します.
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
downX = ev.getX();
break;
case MotionEvent.ACTION_UP:
//
float dx = ev.getX() - downX;
// 1/3
if (dx < mScreenWidth / 3) {
smoothScrollTo(mMenuWidth, 0);
} else {
smoothScrollTo(0, 0);
}
return true;
default:
break;
}
return super.onTouchEvent(ev);
}
このカスタムコントロールは本来デフォルトでスライド可能なのでACTION_を処理する必要はありませんMOVEのイベント.ただACTION_DOWNとACTION_UPイベントではスライドの距離を判断すればよい.スライドの距離がスクリーンの1/3より大きい場合は、サイドバーをスライドさせます.ここでのsmoothScroooTo()メソッドは、すぐに指定された位置にスライドすることはありません.少しゆっくりとスライドします.4スライド中にサイドバーの透明度とサイズと移動効果を変更するカスタムコントロールは、スライド中にonScrolchangedメソッドを複数回コールバックします.
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
//
float factor = (float) l / mMenuWidth;
//
mMenu.setTranslationX(mMenuWidth * factor * 0.6f);
//
float menuScale = 1 - 0.4f * factor;
mMenu.setScaleX(menuScale);
mMenu.setScaleY(menuScale);
//
mMenu.setAlpha(1 - factor);
}
この方法のlはx方向にスライドする距離を表す.したがって、l/サイドバーの幅に従います.スライドのパーセントを計算できます.さらに、スライドの進行率に基づいて、パン、スケール、透明度の効果の値を計算します.ズーム中はサイドバーの幅が小さくなるので、どんどん右に移動します.そうでなければ、サイドバーとメインインタフェースの間には、徐々に効果的な隙間があります.次のように右に移動するとこの隙間はありません.