Merge "WindowInsetsTests: More compelling IME transition sample"
This commit is contained in:
@@ -18,5 +18,10 @@ android_test {
|
||||
resource_dirs: ["res"],
|
||||
certificate: "platform",
|
||||
platform_apis: true,
|
||||
static_libs: [
|
||||
"androidx.core_core",
|
||||
"androidx.appcompat_appcompat",
|
||||
"com.google.android.material_material",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
<application android:label="@string/activity_title">
|
||||
<activity android:name=".WindowInsetsActivity"
|
||||
android:theme="@android:style/Theme.Material"
|
||||
android:theme="@style/appTheme"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
23
tests/WindowInsetsTests/res/drawable/bubble.xml
Normal file
23
tests/WindowInsetsTests/res/drawable/bubble.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2020 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/bubble" />
|
||||
<corners android:radius="@dimen/bubble_corner" />
|
||||
<padding android:left="@dimen/bubble_padding_side" android:top="@dimen/bubble_padding"
|
||||
android:right="@dimen/bubble_padding_side" android:bottom="@dimen/bubble_padding" />
|
||||
</shape>
|
||||
23
tests/WindowInsetsTests/res/drawable/bubble_self.xml
Normal file
23
tests/WindowInsetsTests/res/drawable/bubble_self.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2020 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/bubble_self" />
|
||||
<corners android:radius="@dimen/bubble_corner" />
|
||||
<padding android:left="@dimen/bubble_padding_side" android:top="@dimen/bubble_padding"
|
||||
android:right="@dimen/bubble_padding_side" android:bottom="@dimen/bubble_padding" />
|
||||
</shape>
|
||||
27
tests/WindowInsetsTests/res/drawable/ic_send.xml
Normal file
27
tests/WindowInsetsTests/res/drawable/ic_send.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2020 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:autoMirrored="true"
|
||||
android:width="24.0dp"
|
||||
android:height="24.0dp"
|
||||
android:viewportWidth="48.0"
|
||||
android:viewportHeight="48.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M4.02,42.0L46.0,24.0 4.02,6.0 4.0,20.0l30.0,4.0 -30.0,4.0z"/>
|
||||
</vector>
|
||||
26
tests/WindowInsetsTests/res/layout/message.xml
Normal file
26
tests/WindowInsetsTests/res/layout/message.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2020 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bubble"
|
||||
android:textSize="32sp"
|
||||
android:text="Hello World">
|
||||
|
||||
</TextView>
|
||||
30
tests/WindowInsetsTests/res/layout/message_self.xml
Normal file
30
tests/WindowInsetsTests/res/layout/message_self.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2020 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<merge>
|
||||
<include
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
layout="@layout/message">
|
||||
<aapt:attr name="android:theme">
|
||||
<style>
|
||||
<item name="android:layout_gravity">end</item>
|
||||
<item name="bubbleBackground">@color/bubble_self</item>
|
||||
</style>
|
||||
</aapt:attr>
|
||||
</include>
|
||||
</merge>
|
||||
@@ -17,17 +17,82 @@
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:clipToPadding="false"
|
||||
android:id="@+id/root">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:text="Hello insets" />
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/scrollView"
|
||||
android:layout_height="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/bubble"
|
||||
android:text="Hey, look at this buttery smooth animation!" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/bubble_self"
|
||||
android:text="Wow, that's pretty neat, how does this work?" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/bubble"
|
||||
android:text="Using the new WindowInsets animation system of course!" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:id="@+id/editText">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:hint="Text message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/floating_action_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
app:elevation="0dp"
|
||||
app:fabSize="mini"
|
||||
app:srcCompat="@drawable/ic_send"/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -16,5 +16,5 @@
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="activity_title">Window Insets Tests</string>
|
||||
<string name="activity_title">New Insets Chat</string>
|
||||
</resources>
|
||||
|
||||
67
tests/WindowInsetsTests/res/values/styles.xml
Normal file
67
tests/WindowInsetsTests/res/values/styles.xml
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2020 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<style name="appTheme" parent="@style/Theme.MaterialComponents.Light">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
|
||||
<item name="colorPrimary">@color/primaryColor</item>
|
||||
<item name="colorPrimaryDark">@color/primaryDarkColor</item>
|
||||
<item name="colorSecondary">?attr/colorPrimary</item>
|
||||
<item name="colorOnSecondary">@color/primaryTextColor</item>
|
||||
|
||||
<!-- Window decor -->
|
||||
<item name="android:statusBarColor">#ffffff</item>
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item name="android:windowLightNavigationBar">true</item>
|
||||
<item name="android:navigationBarColor">#ffffff</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="bubble_base" parent="">
|
||||
<item name="android:textSize">20sp</item>
|
||||
<item name="android:layout_marginBottom">16dp</item>
|
||||
</style>
|
||||
|
||||
<style name="bubble" parent="@style/bubble_base">
|
||||
<item name="android:layout_marginEnd">56dp</item>
|
||||
<item name="android:background">@drawable/bubble</item>
|
||||
<item name="android:layout_gravity">start</item>
|
||||
</style>
|
||||
|
||||
<style name="bubble_self" parent="@style/bubble_base">
|
||||
<item name="android:layout_marginStart">56dp</item>
|
||||
<item name="android:background">@drawable/bubble_self</item>
|
||||
<item name="android:layout_gravity">end</item>
|
||||
</style>
|
||||
|
||||
<color name="primaryColor">#1c3fef</color>
|
||||
<color name="primaryLightColor">#6f6bff</color>
|
||||
<color name="primaryDarkColor">#0016bb</color>
|
||||
<color name="primaryTextColor">#ffffff</color>
|
||||
|
||||
<color name="bubble">#eeeeee</color>
|
||||
<color name="bubble_self">#D8DCF0</color>
|
||||
|
||||
<dimen name="bubble_corner">16dp</dimen>
|
||||
<dimen name="bubble_padding">8dp</dimen>
|
||||
<dimen name="bubble_padding_side">16dp</dimen>
|
||||
|
||||
|
||||
</resources>
|
||||
@@ -18,134 +18,216 @@ package com.google.android.test.windowinsetstests;
|
||||
|
||||
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.TypeEvaluator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.app.Activity;
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.graphics.Insets;
|
||||
import android.os.Bundle;
|
||||
import android.util.Property;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.Window;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowInsets.Type;
|
||||
import android.view.WindowInsetsAnimation;
|
||||
import android.view.WindowInsetsAnimation.Callback;
|
||||
import android.view.WindowInsetsAnimationControlListener;
|
||||
import android.view.WindowInsetsAnimationController;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.google.android.test.windowinsetstests.R;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class WindowInsetsActivity extends Activity {
|
||||
public class WindowInsetsActivity extends AppCompatActivity {
|
||||
|
||||
private View mRoot;
|
||||
private View mButton;
|
||||
|
||||
private static class InsetsProperty extends Property<WindowInsetsAnimationController, Insets> {
|
||||
|
||||
private final View mViewToAnimate;
|
||||
private final Insets mShowingInsets;
|
||||
|
||||
public InsetsProperty(View viewToAnimate, Insets showingInsets) {
|
||||
super(Insets.class, "Insets");
|
||||
mViewToAnimate = viewToAnimate;
|
||||
mShowingInsets = showingInsets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets get(WindowInsetsAnimationController object) {
|
||||
return object.getCurrentInsets();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(WindowInsetsAnimationController object, Insets value) {
|
||||
object.setInsetsAndAlpha(value, 1.0f, 0.5f);
|
||||
if (mShowingInsets.bottom != 0) {
|
||||
mViewToAnimate.setTranslationY(mShowingInsets.bottom - value.bottom);
|
||||
} else if (mShowingInsets.right != 0) {
|
||||
mViewToAnimate.setTranslationX(mShowingInsets.right - value.right);
|
||||
} else if (mShowingInsets.left != 0) {
|
||||
mViewToAnimate.setTranslationX(value.left - mShowingInsets.left);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
float startY;
|
||||
float endY;
|
||||
WindowInsetsAnimation imeAnim;
|
||||
final ArrayList<Transition> mTransitions = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.window_inset_activity);
|
||||
|
||||
setSupportActionBar(findViewById(R.id.toolbar));
|
||||
|
||||
mRoot = findViewById(R.id.root);
|
||||
mButton = findViewById(R.id.button);
|
||||
mButton.setOnClickListener(v -> {
|
||||
if (!v.getRootWindowInsets().isVisible(Type.ime())) {
|
||||
v.getWindowInsetsController().show(Type.ime());
|
||||
} else {
|
||||
v.getWindowInsetsController().hide(Type.ime());
|
||||
mRoot.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||
|
||||
mTransitions.add(new Transition(findViewById(R.id.scrollView)));
|
||||
mTransitions.add(new Transition(findViewById(R.id.editText)));
|
||||
|
||||
mRoot.setOnTouchListener(new View.OnTouchListener() {
|
||||
private final ViewConfiguration mViewConfiguration =
|
||||
ViewConfiguration.get(WindowInsetsActivity.this);
|
||||
WindowInsetsAnimationController mAnimationController;
|
||||
WindowInsetsAnimationControlListener mCurrentRequest;
|
||||
boolean mRequestedController = false;
|
||||
float mDown = 0;
|
||||
float mCurrent = 0;
|
||||
Insets mDownInsets = Insets.NONE;
|
||||
boolean mShownAtDown;
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
mCurrent = event.getY();
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mDown = event.getY();
|
||||
mDownInsets = v.getRootWindowInsets().getInsets(Type.ime());
|
||||
mShownAtDown = v.getRootWindowInsets().isVisible(Type.ime());
|
||||
mRequestedController = false;
|
||||
mCurrentRequest = null;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (mAnimationController != null) {
|
||||
updateInset();
|
||||
} else if (Math.abs(mDown - event.getY())
|
||||
> mViewConfiguration.getScaledTouchSlop()
|
||||
&& !mRequestedController) {
|
||||
mRequestedController = true;
|
||||
v.getWindowInsetsController().controlWindowInsetsAnimation(Type.ime(),
|
||||
1000, new LinearInterpolator(),
|
||||
mCurrentRequest = new WindowInsetsAnimationControlListener() {
|
||||
@Override
|
||||
public void onReady(
|
||||
@NonNull WindowInsetsAnimationController controller,
|
||||
int types) {
|
||||
if (mCurrentRequest == this) {
|
||||
mAnimationController = controller;
|
||||
updateInset();
|
||||
} else {
|
||||
controller.finish(mShownAtDown);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelled() {
|
||||
mAnimationController = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if (mAnimationController != null) {
|
||||
boolean isCancel = event.getAction() == MotionEvent.ACTION_CANCEL;
|
||||
mAnimationController.finish(isCancel ? mShownAtDown : !mShownAtDown);
|
||||
mAnimationController = null;
|
||||
}
|
||||
mRequestedController = false;
|
||||
mCurrentRequest = null;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateInset() {
|
||||
int inset = (int) (mDownInsets.bottom + (mDown - mCurrent));
|
||||
final int hidden = mAnimationController.getHiddenStateInsets().bottom;
|
||||
final int shown = mAnimationController.getShownStateInsets().bottom;
|
||||
final int start = mShownAtDown ? shown : hidden;
|
||||
final int end = mShownAtDown ? hidden : shown;
|
||||
inset = max(inset, hidden);
|
||||
inset = min(inset, shown);
|
||||
mAnimationController.setInsetsAndAlpha(
|
||||
Insets.of(0, 0, 0, inset),
|
||||
1f, (inset - start) / (float)(end - start));
|
||||
}
|
||||
});
|
||||
mRoot.setWindowInsetsAnimationCallback(new WindowInsetsAnimation.Callback(
|
||||
DISPATCH_MODE_STOP) {
|
||||
|
||||
mRoot.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
|
||||
@Override
|
||||
public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
|
||||
mRoot.setPadding(insets.getSystemWindowInsetLeft(),
|
||||
insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(),
|
||||
insets.getSystemWindowInsetBottom());
|
||||
return WindowInsets.CONSUMED;
|
||||
}
|
||||
});
|
||||
|
||||
mRoot.setWindowInsetsAnimationCallback(new Callback(DISPATCH_MODE_STOP) {
|
||||
|
||||
@Override
|
||||
public void onPrepare(WindowInsetsAnimation animation) {
|
||||
if ((animation.getTypeMask() & Type.ime()) != 0) {
|
||||
imeAnim = animation;
|
||||
}
|
||||
startY = mButton.getTop();
|
||||
mTransitions.forEach(it -> it.onPrepare(animation));
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowInsets onProgress(WindowInsets insets,
|
||||
List<WindowInsetsAnimation> runningAnimations) {
|
||||
mButton.setY(startY + (endY - startY) * imeAnim.getInterpolatedFraction());
|
||||
@NonNull List<WindowInsetsAnimation> runningAnimations) {
|
||||
mTransitions.forEach(it -> it.onProgress(insets));
|
||||
return insets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowInsetsAnimation.Bounds onStart(WindowInsetsAnimation animation,
|
||||
WindowInsetsAnimation.Bounds bounds) {
|
||||
endY = mButton.getTop();
|
||||
mTransitions.forEach(Transition::onStart);
|
||||
return bounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnd(WindowInsetsAnimation animation) {
|
||||
imeAnim = null;
|
||||
mTransitions.forEach(it -> it.onFinish(animation));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
// TODO: move this to onCreate once setDecorFitsSystemWindows can be safely called there.
|
||||
getWindow().getDecorView().post(() -> getWindow().setDecorFitsSystemWindows(false));
|
||||
}
|
||||
|
||||
TypeEvaluator<Insets> evaluator = (fraction, startValue, endValue) -> Insets.of(
|
||||
(int)(startValue.left + fraction * (endValue.left - startValue.left)),
|
||||
(int)(startValue.top + fraction * (endValue.top - startValue.top)),
|
||||
(int)(startValue.right + fraction * (endValue.right - startValue.right)),
|
||||
(int)(startValue.bottom + fraction * (endValue.bottom - startValue.bottom)));
|
||||
static class Transition {
|
||||
private int mEndBottom;
|
||||
private int mStartBottom;
|
||||
private final View mView;
|
||||
private WindowInsetsAnimation mInsetsAnimation;
|
||||
|
||||
WindowInsetsAnimationControlListener listener = new WindowInsetsAnimationControlListener() {
|
||||
@Override
|
||||
public void onReady(WindowInsetsAnimationController controller, int types) {
|
||||
ObjectAnimator animator = ObjectAnimator.ofObject(controller,
|
||||
new InsetsProperty(findViewById(R.id.button),
|
||||
controller.getShownStateInsets()),
|
||||
evaluator, controller.getShownStateInsets(),
|
||||
controller.getHiddenStateInsets());
|
||||
animator.setRepeatCount(ValueAnimator.INFINITE);
|
||||
animator.setRepeatMode(ValueAnimator.REVERSE);
|
||||
animator.start();
|
||||
Transition(View root) {
|
||||
mView = root;
|
||||
}
|
||||
|
||||
void onPrepare(WindowInsetsAnimation animation) {
|
||||
if ((animation.getTypeMask() & Type.ime()) != 0) {
|
||||
mInsetsAnimation = animation;
|
||||
}
|
||||
mStartBottom = mView.getBottom();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelled() {
|
||||
void onProgress(WindowInsets insets) {
|
||||
mView.setY(mStartBottom + (mEndBottom - mStartBottom)
|
||||
* mInsetsAnimation.getInterpolatedFraction()
|
||||
- mView.getHeight());
|
||||
}
|
||||
|
||||
void onStart() {
|
||||
mEndBottom = mView.getBottom();
|
||||
}
|
||||
|
||||
void onFinish(WindowInsetsAnimation animation) {
|
||||
if (mInsetsAnimation == animation) {
|
||||
mInsetsAnimation = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static class ImeLinearLayout extends LinearLayout {
|
||||
|
||||
public ImeLinearLayout(Context context,
|
||||
@Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user