web-dev-qa-db-ja.com

フローティングボタンのようにスナックバーの上にビューを移動する方法

スナックバーが表示されたときに上に移動したい直線的なレイアウトを取得しました。

Floating Buttonでこれを行う方法の例をたくさん見ましたが、通常のビューはどうですか?

40
Ilya Gazman

LinearLayoutに動作を追加し、CoordinatorLayoutに埋め込む必要があります。あなたはこれを読みたいかもしれません: http://alisonhuang-blog.logdown.com/posts/290009-design-support-library-coordinator-layout-and-behavior

15
ligi

承認済みの回答について詳しく説明します。なぜなら、この記事が提供するよりも実装が少し単純だと思うからです。

ビューの一般的な移動を処理する組み込みの動作を見つけることができませんでしたが、これは適切な汎用オプションです( http://alisonhuang-blog.logdown.com/posts/290009から) -design-support-library-coordinator-layout-and-behavior 別のコメントにリンク)

import Android.content.Context;
import Android.support.annotation.Keep;
import Android.support.design.widget.CoordinatorLayout;
import Android.support.design.widget.Snackbar;
import Android.support.v4.view.ViewCompat;
import Android.util.AttributeSet;
import Android.view.View;

@Keep
public class MoveUpwardBehavior extends CoordinatorLayout.Behavior<View> {

    public MoveUpwardBehavior() {
        super();
    }

    public MoveUpwardBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        return dependency instanceof Snackbar.SnackbarLayout;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        float translationY = Math.min(0, ViewCompat.getTranslationY(dependency) - dependency.getHeight());
        ViewCompat.setTranslationY(child, translationY);
        return true;
    }

    //you need this when you swipe the snackbar(thanx to ubuntudroid's comment)
    @Override
    public void onDependentViewRemoved(CoordinatorLayout parent, View child, View dependency) {
        ViewCompat.animate(child).translationY(0).start();
    }
}

次に、レイアウトファイルに以下のようにlayout_behaviorを追加します。

<LinearLayout
    Android:id="@+id/main_content"
    Android:orientation="vertical"
    app:layout_behavior="com.example.MoveUpwardBehavior"/>

ここで、layout_behaviorは、カスタム動作へのフルパスです。珍しいと思われるデフォルトの動作を特別に必要としない限り、LinearLayoutをサブクラス化する必要はありません。

68
Travis Castillo

@Travis Castilloの回答に基づきます。以下のような修正された問題:

Moving entire layout up and cause the objects on top of view disappear.
Doesnt Push the layout up when showing SnackBars immediately after eachother.

そのため、MoveUpwardBehaviorクラスの固定コードは次のとおりです。

import Android.content.Context;
import Android.support.annotation.Keep;
import Android.support.design.widget.CoordinatorLayout;
import Android.support.design.widget.Snackbar;
import Android.support.v4.view.ViewCompat;
import Android.util.AttributeSet;
import Android.view.View;

@Keep
public class MoveUpwardBehavior extends CoordinatorLayout.Behavior<View> {

    public MoveUpwardBehavior() {

        super();

    }

    public MoveUpwardBehavior(Context context, AttributeSet attrs) {

        super(context, attrs);

    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {

        return dependency instanceof Snackbar.SnackbarLayout;

    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {

        float translationY = Math.min(0, ViewCompat.getTranslationY(dependency) - dependency.getHeight());

        //Dismiss last SnackBar immediately to prevent from conflict when showing SnackBars immediately after eachother
        ViewCompat.animate(child).cancel();

        //Move entire child layout up that causes objects on top disappear
        ViewCompat.setTranslationY(child, translationY);

        //Set top padding to child layout to reappear missing objects
        //If you had set padding to child in xml, then you have to set them here by <child.getPaddingLeft(), ...>
        child.setPadding(0, -Math.round(translationY), 0, 0);

        return true;
    }

    @Override
    public void onDependentViewRemoved(CoordinatorLayout parent, View child, View dependency) {

        //Reset paddings and translationY to its default
        child.setPadding(0, 0, 0, 0);
        ViewCompat.animate(child).translationY(0).start();

    }
}

このコードは、ユーザーが画面に表示するものを押し上げ、さらにユーザーはSnackBarの表示中にレイアウト内のすべてのオブジェクトにアクセスできます。

SnackBarがプッシュの代わりにオブジェクトをカバーし、ユーザーがすべてのオブジェクトにアクセスできるようにする場合は、メソッドを変更する必要がありますonDependentViewChanged:

@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {

    float translationY = Math.min(0, ViewCompat.getTranslationY(dependency) - dependency.getHeight());

    //Dismiss last SnackBar immediately to prevent from conflict when showing SnackBars immediately after eachother
    ViewCompat.animate(child).cancel();

    //Padding from bottom instead pushing top and padding from top.
    //If you had set padding to child in xml, then you have to set them here by <child.getPaddingLeft(), ...>
    child.setPadding(0, 0, 0, -Math.round(translationY));

    return true;
}

およびメソッドonDependentViewRemoved:

@Override
public void onDependentViewRemoved(CoordinatorLayout parent, View child, View dependency) {

    //Reset paddings and translationY to its default
    child.setPadding(0, 0, 0, 0);

}

残念ながら、ユーザーがスナックバーを削除するためにスワイプするとアニメーションが失われます。そして、ValueAnimatorクラスを使用して、パディングの変更のアニメーションを作成する必要があります。

https://developer.Android.com/reference/Android/animation/ValueAnimator.html

SnackBarを削除するためのスワイプのアニメーションに関するコメントは歓迎します。

そのアニメーションをスキップできる場合は、使用できます。

とにかく、私は最初のタイプをお勧めします。

16
Alirezaa

これを実装し、スナックバーが消えると、スナックバーの場所に白いスペースが表示されたままであることがわかりました。これは、デバイスでアニメーションが無効になっている場合は明らかです。

これを修正するために、onDependentViewChangedメソッドを変更して、このビヘイビアーが関連付けられているビューの最初のY位置を保存しました。次に、スナックバーを取り外すと、そのビューの位置を保存されたY位置にリセットします

private static float initialPositionY;

@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
    initialPositionY = child.getY();
    float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight());
    child.setTranslationY(translationY);
    return true;
}

@Override
public void onDependentViewRemoved(CoordinatorLayout parent, View child, View dependency) {
    super.onDependentViewRemoved(parent, child, dependency);
    child.setTranslationY(initialPositionY);
}
3
Charles Barter

Travis Castilloの答えに加えて、onDependentViewChanged()内で連続したSnackBarsをトリガーできるようにするには、onDependentViewRemoved()によって開始された可能性のあるアニメーションをキャンセルする必要があります。

@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
    float translationY = Math.min(0, ViewCompat.getTranslationY(dependency) - dependency.getHeight());
    ViewCompat.animate(child).cancel(); //cancel potential animation started in onDependentViewRemoved()
    ViewCompat.setTranslationY(child, translationY);
    return true;
}

キャンセルしない場合、SnackBarが別のSnackBarに置き換えられると、LinearLayoutは2番目のSnackBarの下にジャンプします。

1
Tromse

SnackProgressBarでアニメーション化するために追加のビューを追加できるライブラリを作成しました。また、progressBarおよびその他のものも含まれます。試してみてください https://github.com/tingyik90/snackprogressbar

アニメーション化する次のビューがあるとします。

View[] views = {view1, view2, view3};

アクティビティにSnackProgressBarManagerのインスタンスを作成し、アニメーション化するビューを含めます。

SnackProgressBarManager snackProgressBarManager = new SnackProgressBarManager(rootView)
        .setViewsToMove(views)

SnackProgressBarが表示または非表示にされると、これらのビューはそれに応じてアニメーション化されます。

0
tingyik90