AndroidはQQのサイドバーに似ています


まず効果図を見てみましょう.
メインインタフェースの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/サイドバーの幅に従います.スライドのパーセントを計算できます.さらに、スライドの進行率に基づいて、パン、スケール、透明度の効果の値を計算します.ズーム中はサイドバーの幅が小さくなるので、どんどん右に移動します.そうでなければ、サイドバーとメインインタフェースの間には、徐々に効果的な隙間があります.次のように
右に移動するとこの隙間はありません.