カスタムDrawerLayoutドロワーレイアウト

最近、プロジェクトは引き出しのスライド効果を作成する必要があります。つまり、次のように画面の右側からページをスライドさせます。

非常にシンプルで、システムに付属するDrawerLayoutは、このような基本的な要件を満たすことができます。ただし、要件はもう少し複雑です。サイドバーを閉じる前に、データの保存を行います。現時点で何をしますか?このことにはスライディングモニターが必要だと誰もが思うと思います。スライディングイベントを監視するのは良いことではないでしょうか。それでは、Drawerlayoutのスライディングモニターを見てみましょう。コードは次のとおりです。

 

mDrawerLayout.addDrawerListener(new MyDrawerLayout.DrawerListener(){
            @オーバーライド
            public  void onDrawerSlide(@NonNull View var1、float var2){
                
            }

            @オーバーライド
            public  void onDrawerOpened(@NonNull View var1){

            }

            @オーバーライド
            public  void onDrawerClosed(@NonNull View var1){

            }

            @オーバーライド
            public  void onDrawerStateChanged(int var1){

            }
        });

 

このシステムでは4つのスライドモニターが提供されていることがわかります。ニーズに最適な方法はこの方法のようです。

 
 
@Override 
public void onDrawerClosed(@NonNull View var1){

}
 

 

 

では、閉じるアクションが始まる前にページにコールバックできますか?答えはノーです!すぐにサイドバーのスライドの終了後に、それは、その後のアクションをスライドさせ、画面の外に徹底的にサイドバーのスライドまで、となりますので、この方法は完全に終了し、この方法!Emmmm、くそ実行されますと呼ばれているAAAを

他の方法は使いやすいですか?答えは、簡単ではない、なぜ使いにくいのか、みんなで個人的に試してみるので、ここでは説明しません。

では、どうすればいいのでしょうか?長い間インターネットを検索する良い方法はなく、自分でホイールを作る方法はありません。

 

最初にアイデアを整理します。このようなメソッドが必要です。

beforeClose()

 

このメソッドの実行時間は、サイドバーの閉じるアクションの前、つまり、画面の白い部分をクリックすると、システムはデフォルトの閉じる操作を実行せず、このメソッドを実行します(beforeClose())私たちのビジネスのコードの実行を終了し、デフォルトクローズ操作を移動するときに、この方法では、当社の事業のコードを実行し、その後、切片にデフォルトのシステムシャットダウンで出てきたに沿って考えて、[OK]を、我々はアドレスに持っています問題です。

最初の質問は、まずシステムのデフォルトのシャットダウン操作がどこに書かれているかを見つけます。どこに書き込むかについて、システムのデフォルトのシャットダウンプロセスを詳しく見てみましょう。まず、画面の空白部分をクリックします。対応するタッチイベントは  ACTION_DOWNであるはず   です。その後、画面から解放することについて心配する必要はありません。 、この時点でサイドバーのスライドを確認しましたか?答えはノーです!したがって、これは ACTION_DOWN ステップでサイドバーのクローズイベントが実行されなかったことを証明します。次に、指を離すと、 ACTION_UPがこの時点実行されるはずです。 サイドバーが後ろにスライドします。このステップは、システムのデフォルトのシャットダウンメソッドが ACTION_UP イベントの下にあることを証明しています  。ソースコードのコードのこの部分を見ると、次のように簡単に見つけることができます。

 

public  boolean onTouchEvent(MotionEvent ev){
      ……
        スイッチ(アクション&255 ){
             ケース ACTION_DOWN 
               ........
                休憩;
            ケース ACTION_UP 
                x = ev.getX();
                y = ev.getY();
                boolean peekingOnly = true ;
                ビューtouchedView = this .mLeftDragger.findTopChildUnder((int)x、(int )y);
                if(touchedView!= null && this .isContentView(touchedView)){
                     float dx = x- this .mInitialMotionX;
                    float dy = y- this .mInitialMotionY;
                    int slop = this .mLeftDragger.getTouchSlop();
                    if(dx * dx + dy * dy <(float)(slop * slop)){
                        openDrawer = this .findOpenDrawer();を表示しますif(openDrawer!= null ){
                            peekingOnly = this .getDrawerLockMode(openDrawer)== 2 ;
                        }
                    }
                }

                this .closeDrawers(peekingOnly);

                this .mDisallowInterceptRequested = false ;
           ..............
        }

        wantTouchEventsを返します。
    }

 

 

多くのコードがあり、無関係なコンテンツはスキップされます。ここでは重要なコードのみを確​​認し、onTouchEventのACTION_UPアクションの下にそのようなメソッドを見つけました。

 this .closeDrawers(peekingOnly); 
つまり:
void closeDrawers(boolean peekingOnly){ 
boolean needsInvalidate = false;
final int childCount = getChildCount();
for(int i = 0; i <childCount; i ++){
final View child = getChildAt(i);
final LayoutParams lp =(LayoutParams)child.getLayoutParams();

if(!isDrawerView(child)||(peekingOnly &&!lp.isPeeking)){
続行;
}

final int childWidth = child.getWidth();

if(checkDrawerViewAbsoluteGravity(child、Gravity.LEFT)){
needsInvalidate | = mLeftDragger.smoothSlideViewTo(child、
-childWidth、child.getTop());
} そうしないと {
needsInvalidate | = mRightDragger.smoothSlideViewTo(child、
getWidth()、child.getTop());
}

lp.isPeeking = false;
}

mLeftCallback.removeCallbacks()。
mRightCallback.removeCallbacks();

if(needsInvalidate){
invalidate();
}
}

 

これは私たちが探しているものですか?これがそのようなコードです:

mLeftDragger.smoothSlideViewTo(..、..、..)

 

メソッド名がわくわくしないことを見て、メソッド名を翻訳して、スムーズな側面図を...に変えてください。確認方法は?デバッグを開いて、独自のブレークポイントで確認します。そうです。

 

OK、ほとんどの作業はここで行われ、残りはcloseDrawersでこのメソッドの呼び出しをインターセプトし、ビジネスコードを実行して、このコードを呼び出すことです。

 

一部の友人は尋ねるかもしれませんが、drawerlayoutはシステムの制御であり、変更することはできません。コードを変更することはできません。どのようにインターセプトするのですか?ハハ、システムは私たちが変更することを許可していません、私たちが自分で新しいクラスを作成することはできません、コードはシステムを直接コピーしてそれは終了します。

したがって、次のようなものがあります。

パッケージcom.zhd.life.helloworld2;
........
 パブリック クラス MyDrawerLayout extends ViewGroup {
    public MyDrawerLayout(@NonNull Context context){
         this(context、(AttributeSet)null );
    }

    public MyDrawerLayout(@NonNull Context context、@Nullable AttributeSet attrs){
         this(context、attrs、0 );
    }

    public MyDrawerLayout(@NonNull Context context、@Nullable AttributeSet attrs、int defStyle){
       
    }

   ....... 
}

 

新しいクラスを作成します。MyDrawerLayoutという名前を付けると、コード内のすべての詳細がシステムに直接コピーされ、1点は変更されません。今回は変更しますか?

ビューのスライドがMyDrawerLayoutにあり、ビジネスコードがアクティビティにあるため、インターセプトを開始します。次に、closeDrawers()メソッドが呼び出される前にアクティビティに通知する必要があります。コールバック、イベントバス、機能します。ここでは、インターフェースコールバックの方法を選択しますが、なぜこれを選択するのですか?私はそれに慣れています誰もがそのように慣れています誰もが自分のためにそれを選択します

まず、次のようにインターフェースを定義します。

パブリック インターフェイスOnClickWiteLisener {
         void beforeClose();
    }

 

MydrawerLayoutのcloseDrawersに書き込みます。

void closeDrawers(boolean peekingOnly){
        needsInvalidate = false ;
        int childCount = this .getChildCount();
        forint i = 0; i <childCount; ++ i){
         ...........
            ifthis .isDrawerView(child)&&(!peekingOnly || lp.isPeeking)){

                if(mOnClickWiteLisener!= null ){
                    mOnClickWiteLisener.beforeClose();
                } その他{
                    閉じる();
                }
            }
        }

        this .mLeftCallback.removeCallbacks();
        this .mRightCallback.removeCallbacks();
        if (needsInvalidate){
             this .invalidate();
        }

    }    

 

 

closeメソッドは次のとおりです。

   プライベートビューの子。
    プライベート ブール needsInvalidate = false ;
    プライベートMyDrawerLayout.LayoutParams lp;

    public  void close(){
         int childWidth = child.getWidth();
        ifthis .checkDrawerViewAbsoluteGravity(child、3 )){
            needsInvalidate | = this .mLeftDragger.smoothSlideViewTo(child、-childWidth、child.getTop());
        } その他{
            needsInvalidate | = this .mRightDragger.smoothSlideViewTo(child、this .getWidth()、child.getTop());
        }

        lp.isPeeking = false ;
    }

 

これでインターセプト機能が完成しました。アクティビティにOnClickWiteLisenerを実装すると、定義したコールバックを実行します。実装しない場合は、元のシステムフローを続行します。

このような活動で使用され、

パブリック クラス MainActivity は、 AppCompatActivityを拡張してMyDrawerLayout.OnClickWiteLisener {

    // カスタムMyDrawerLayout 
    プライベートMyDrawerLayout mDrawerLayout;

    // このボタンをクリックして、サイドバーの
    プライベートTextViewショーを開きます

    @オーバーライド
    protected  void onCreate(Bundle savedInstanceState){
         super .onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDrawerLayout = findViewById(R.id.aaa);
        show = findViewById(R.id.show);
        mDrawerLayout.setOnClickWiteLisener(this );
        show.setOnClickListener(new View.OnClickListener(){
            @オーバーライド
            public  void onClick(View v){
                mDrawerLayout.openDrawer(Gravity.END);
            }
        });
    }

    @オーバーライド
    public  void beforeClose(){
        Toast.makeText(これは、「白い画面をクリックして閉じたいので、ここでデータの保存操作を実行しました」、Toast.LENGTH_SHORT).show();
        mDrawerLayout.close();
    }
}

 

 

了解しました。それだけです。

眠い

 

おすすめ

転載: www.cnblogs.com/zhdsky/p/12670870.html