Подтвердить что ты не робот

Анимация изменения макета нижнего листа

В моем приложении я использую нижний лист (из библиотеки поддержки), который отлично работает. Теперь я хотел бы оживить изменение макета, пока лист перетаскивается. Для этого я создал подкласс BottomSheetCallback (это нормальный внутренний класс фрагмента, поэтому здесь не все объекты, используемые в этих calss):

public class MyBehavior extends BottomSheetBehavior.BottomSheetCallback {

    Transition transition;
    float lastOffset = 0;
    Scene scene;

    public PlayerBehavior() {
        TransitionInflater inflater = TransitionInflater.from(getContext());
        transition = inflater.inflateTransition(R.transition.player);
        //transition.setDuration(300);

        scene = fullLayout;

        transition.setInterpolator(new Interpolator() {
            @Override
            public float getInterpolation(float v) {
                return lastOffset;
            }
        });
    }

    @Override
    public void onStateChanged(@NonNull View bottomSheet, int newState) {
        if(newState == BottomSheetBehavior.STATE_DRAGGING) {
            TransitionManager.go(scene, transition);
        }
    }

    @Override
    public void onSlide(View bottomSheet, final float slideOffset) {
        scene = (slideOffset > lastOffset) ? smallLayout : fullLayout;
        lastOffset = slideOffset;
    }
}

Как вы можете видеть, я также создал два Scene из разных файлов макета и пользовательский Transition для анимации между сценами с помощью TransitionManager. Моя проблема заключается в том, что Transition должен быть основан на параметре slideOffset (в диапазоне от 0 до 1), но TransitionManager использует класс Animation в фоновом режиме, который, как правило, основан на времени в Android.

Я попытался создать пользовательский Intapolator, но это не работает должным образом. Итак, как я могу создать Transition, который основан на внешней переменной, а не во времени?

4b9b3361

Ответ 1

Основываясь на вашем описании, я думаю, что вы пытаетесь достичь чего-то вроде поведения нижнего листа карты Google. Макет изменяется при перетаскивании нижнего листа.

Если это то, чего вы пытаетесь достичь, вам не нужно принудительно выполнять пользовательские анимации, так как сам нижний индекс сам по себе имеет такое поведение анимации, когда он встроен в родительский Макет координатора.

Вот пример кода того, как я реализую одно и то же поведение. Это также делает невидимым FloatingActionButton, когда нижний лист перетаскивается до полного размера экрана:

  • Создайте нижестоящий указатель, который вы хотите использовать внутри основного макета

    public class CustomBottomDialog extends BottomSheetDialogFragment {
    
    String mSomeName;
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // if some arguments are passed from the calling activity 
        mSomeName = getArguments().getString("some_name");
    
    
    }
    
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View bottomSheet = inflater.inflate(R.layout.bottomsheet_layout, container, false);
         // initialise your bottomsheet_layout items here 
        TextView tvName = bottomSheet.findViewById(R.id.display_name);
        tvName.setText(mSomeName); 
        tvName.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
               // do something here
                ((MainActivity)getActivity()).doSomething();
            }
        });
    
        return bottomSheet;
    }
    }
    
  • Bottomsheet_layout:

    <android.support.design.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <android.support.design.widget.FloatingActionButton
    android:id="@+id/nav"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/navigation_tilt_grey"
    app:backgroundTint="@color/colorAccent"
    app:elevation="3dp"
    app:fabSize="normal"
    android:layout_marginEnd="@dimen/activity_horizontal_margin"
    app:layout_anchor="@+id/live_dash"
    app:layout_anchorGravity="top|right" />
    
    <!--BottomSheet-->
    
    <android.support.v4.widget.NestedScrollView
    android:id="@+id/live_dash"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#F3F3F3"
    android:clipToPadding="true"
    app:layout_behavior="android.support.design.widget.BottomSheetBe 
    havior"
    tools:layout_editor_absoluteY="150dp">
    
    <!--Include your items here, the height of all items combined
    will take the main screen layout size with animation-->
    
    </android.support.v4.widget.NestedScrollView>
    
    </android.support.design.widget.CoordinatorLayout>
    
  • Вызов этого нижнего листа из вашей активности:

    public void notifyBottomSheet(String somename){
    
    BottomSheetDialogFragment customDialogFragment = new CustomBottomDialog();
    Bundle args = new Bundle();
    args.putString("some_name", somename);
    customDialogFragment.setArguments(args);
    customDialogFragment.show(getSupportFragmentManager(), customDialogFragment.getTag());
    customDialogFragment.setCancelable(false); // if you don't wish to hide
    }
    

    Надеюсь, это решит то, чего вы пытаетесь достичь.

Ответ 2

Я не уверен, что это то, что вы хотите, но, возможно, вместо использования перехода, вы можете использовать функцию animate(), поскольку с помощью этой функции вы можете изменить все о своей анимации (время, видимость и т.д.).

Ответ 3

## Translation Animation ##
<?xml version="1.0" encoding="utf-8"?>
<set
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:fillAfter="true"
    >
    <translate
        android:fromYDelta="100%p"
        android:toYDelta="-30%p"
        android:duration="900" />
</set>

## Основная деятельность ##

@Override
protected void onResume() {
    super.onResume();
    Animation am= AnimationUtils.loadAnimation(this,R.anim.fadeout);
    tv5.startAnimation(am);
    Animation myanim= AnimationUtils.loadAnimation(this,R.anim.translate);
    tv1.startAnimation(myanim);
    myanim.setStartOffset(500);
    Animation animation= AnimationUtils.loadAnimation(this,R.anim.translate);
    animation.setStartOffset(1000);
    tv2.startAnimation(animation);
    Animation an= AnimationUtils.loadAnimation(this,R.anim.translate);
    an.setStartOffset(1500);
    tv3.startAnimation(an);
    Animation ab= AnimationUtils.loadAnimation(this,R.anim.translate);
    ab.setStartOffset(2000);
    tv4.startAnimation(ab);
    Animation ac= AnimationUtils.loadAnimation(this,R.anim.fadein);
    ac.setStartOffset(2500);
    btn1.startAnimation(ac);
}

Ответ 4

Чтобы легко сдвинуть что-то в нижней части экрана, вы можете использовать код, например:

final int activityHeight = findViewById(android.R.id.content).getHeight();
cardContainer.animate().yBy(activityHeight - cardContainer.getY()).setDuration(SLIDE_OUT_DURATION);

где cardContainer - это вид, который вы пытаетесь сместить с экрана.

Смотрите этот сообщение в блоге для полного примера. Обратите внимание, что вы также можете использовать translationY вместо yBy. Другой, более общий способ сделать это с помощью этого кода:

public static ViewPropertyAnimator slideOutToBottom(Context ctx, View view) {
    final int screenHeight = ctx.getResources().getDisplayMetrics().heightPixels;
    int[] coords = new int[2];
    view.getLocationOnScreen(coords);
    return view.animate().translationY(screenHeight - coords[Y_INDEX]).setDuration(SLIDE_OUT_DURATION);
}

public static ViewPropertyAnimator slideInFromBottom(Context ctx, View view) {
    final int screenHeight = ctx.getResources().getDisplayMetrics().heightPixels;
    int[] coords = new int[2];
    view.getLocationOnScreen(coords);
    view.setTranslationY(screenHeight - coords[Y_INDEX]);
    return view.animate().translationY(0).setDuration(SLIDE_IN_DURATION).setInterpolator(new OvershootInterpolator(1f));
}