android----側(cè)邊欄(DrawerLayout)(完美解決只能在邊緣滑出)

一步一步
第一步: 創(chuàng)建空項(xiàng)目

image.png

第二步: 修改布局文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000">

<!--  主頁(yè)面  -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#fff"
        >
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="首頁(yè)"
            />
    </LinearLayout>

<!--  側(cè)邊欄  -->
    <LinearLayout
        android:id="@+id/drawer_start"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#eda02c"
        android:layout_gravity="start"
        >
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="側(cè)邊欄"
            android:textColor="#fff"
            />
    </LinearLayout>

</androidx.drawerlayout.widget.DrawerLayout>

此時(shí)app效果圖為:


cebianlan_demo.gif

可以看到只能從邊緣觸發(fā)側(cè)邊欄, 想要類(lèi)似qq側(cè)邊欄, 可以從中間滑出來(lái), 網(wǎng)上有大部分有兩種方法, 一種反射修改mEdgeSize的值來(lái)實(shí)現(xiàn), 另一種通過(guò)activity事件分發(fā)配合mDrawerLayout.opDrawer(GravityCompat.START)來(lái)實(shí)現(xiàn), 后者必須手指離開(kāi)屏幕才能觸發(fā), 體驗(yàn)不好, 我們這里用第一種方法, 通過(guò)反射修改mEdgeSize的值

在onCreate()方法里進(jìn)行編寫(xiě)

    DrawerLayout mDrawerLayout;//根布局
    LinearLayout mLinearLayout;//側(cè)邊欄布局
    View mContent;//主頁(yè)面布局

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //--------------------START--------------------------------
        mDrawerLayout = findViewById(R.id.drawer_layout_root);//獲取根布局
        mLinearLayout = findViewById(R.id.drawer_start);//獲取側(cè)邊欄布局
        mContent = mDrawerLayout.getChildAt(0);//獲取主頁(yè)面布局, 可以看到主頁(yè)面布局是父布局的第一個(gè)子布局, 可以這樣獲得, 也可以定義id

        try {
            Field leftDraggerField = mDrawerLayout.getClass().getDeclaredField("mLeftDragger");//通過(guò)反射獲得DrawerLayout類(lèi)中mLeftDragger字段
            leftDraggerField.setAccessible(true);//私有屬性要允許修改
            ViewDragHelper vdh = (ViewDragHelper) leftDraggerField.get(mDrawerLayout);//獲取ViewDragHelper的實(shí)例, 通過(guò)ViewDragHelper實(shí)例獲取mEdgeSize字段
            Field edgeSizeField = vdh.getClass().getDeclaredField("mEdgeSize");//依舊是通過(guò)反射獲取ViewDragHelper類(lèi)中mEdgeSize字段, 這個(gè)字段控制邊緣觸發(fā)范圍
            edgeSizeField.setAccessible(true);//依然是私有屬性要允許修改
            int edgeSize = edgeSizeField.getInt(vdh);//這里獲得mEdgeSize真實(shí)值
            Log.d("AAA", "mEdgeSize: "+edgeSize);//這里可以打印一下看看值是多少

            //Start 獲取手機(jī)屏幕寬度,單位px
            Point point = new Point();
            getWindowManager().getDefaultDisplay().getRealSize(point);
            //End 獲取手機(jī)屏幕

            Log.d("AAA", "point: "+point.x);//依然可以打印一下看看值是多少
            edgeSizeField.setInt(vdh, Math.max(edgeSize, point.x));//這里設(shè)置mEdgeSize的值!??!,Math.max函數(shù)取得是最大值,也可以自己指定想要觸發(fā)的范圍值,如: 500,注意單位是px
            //寫(xiě)到這里已經(jīng)實(shí)現(xiàn)了,但是你會(huì)發(fā)現(xiàn),如果長(zhǎng)按觸發(fā)范圍,側(cè)邊欄也會(huì)彈出來(lái),而且速度不太同步,穩(wěn)定

            //Start 解決長(zhǎng)按會(huì)觸發(fā)側(cè)邊欄
            //長(zhǎng)按會(huì)觸發(fā)側(cè)邊欄是DrawerLayout類(lèi)的私有類(lèi)ViewDragCallback中的mPeekRunnable實(shí)現(xiàn)導(dǎo)致,我們通過(guò)反射把它置空
            Field leftCallbackField = mDrawerLayout.getClass().getDeclaredField("mLeftCallback");//通過(guò)反射拿到私有類(lèi)ViewDragCallback字段
            leftCallbackField.setAccessible(true);//私有字段設(shè)置允許修改
            ViewDragHelper.Callback vdhCallback = (ViewDragHelper.Callback) leftCallbackField.get(mDrawerLayout);//ViewDragCallback類(lèi)是私有類(lèi),我們返回類(lèi)型定義成他的父類(lèi)
            Field peekRunnableField = vdhCallback.getClass().getDeclaredField("mPeekRunnable");//我們依然是通過(guò)反射拿到關(guān)鍵字段,mPeekRunnable
            peekRunnableField.setAccessible(true);//不解釋了
            //定義一個(gè)空的實(shí)現(xiàn)
            Runnable nullRunnable = new Runnable(){
                @Override
                public void run() {

                }
            };
            peekRunnableField.set(vdhCallback, nullRunnable);//給mPeekRunnable字段置空
            //End 解決長(zhǎng)按觸發(fā)側(cè)邊欄

        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        //--------------------END--------------------------------
    }

至此側(cè)邊欄邊緣問(wèn)題解決,與當(dāng)前版本qq側(cè)邊欄一樣


cebianlan_demo_finish.gif

原文鏈接:
完美開(kāi)啟DrawerLayout全屏手勢(shì)側(cè)滑 - 簡(jiǎn)書(shū) (jianshu.com)
以上解決方案搬的是評(píng)論中 Febers 的評(píng)論?。。?/p>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容