mirror of
https://github.com/Tencent/QMUI_Android.git
synced 2026-10-29 11:37:07 +08:00
bugfix: add api 19 support for QMUICollapsingTopBarLayout.#40
This commit is contained in:
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.support.design.widget.AppBarLayout;
|
||||
import android.support.design.widget.CoordinatorLayout;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v4.view.WindowInsetsCompat;
|
||||
@@ -13,7 +14,6 @@ import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.qmuiteam.qmui.widget.IWindowInsetLayout;
|
||||
import com.qmuiteam.qmui.widget.QMUIWindowInsetLayout;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
@@ -68,8 +68,15 @@ public class QMUIWindowInsetHelper {
|
||||
Rect childInsets = new Rect(insets);
|
||||
computeInsetsWithGravity(child, childInsets);
|
||||
|
||||
child.setPadding(childInsets.left, childInsets.top, childInsets.right, childInsets.bottom);
|
||||
|
||||
if (!isHandleContainer(child)) {
|
||||
child.setPadding(childInsets.left, childInsets.top, childInsets.right, childInsets.bottom);
|
||||
} else {
|
||||
if (child instanceof IWindowInsetLayout) {
|
||||
((IWindowInsetLayout) child).applySystemWindowInsets19(childInsets);
|
||||
} else {
|
||||
defaultApplySystemWindowInsets19((ViewGroup) child, childInsets);
|
||||
}
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
@@ -114,10 +121,13 @@ public class QMUIWindowInsetHelper {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@TargetApi(19)
|
||||
private boolean jumpDispatch(View child) {
|
||||
return !child.getFitsSystemWindows() &&
|
||||
!(child instanceof QMUIWindowInsetLayout) &&
|
||||
!(child instanceof CoordinatorLayout);
|
||||
public static boolean jumpDispatch(View child) {
|
||||
return !child.getFitsSystemWindows() && !isHandleContainer(child);
|
||||
}
|
||||
|
||||
public static boolean isHandleContainer(View child) {
|
||||
return child instanceof IWindowInsetLayout ||
|
||||
child instanceof CoordinatorLayout;
|
||||
}
|
||||
|
||||
@SuppressLint("RtlHardcoded")
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.qmuiteam.qmui.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.support.design.widget.AppBarLayout;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v4.view.WindowInsetsCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import com.qmuiteam.qmui.util.QMUIWindowInsetHelper;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* add support for API 19 when use with {@link android.support.design.widget.CoordinatorLayout}
|
||||
* and {@link QMUICollapsingTopBarLayout}
|
||||
*
|
||||
* notice: we use reflection to change the field value in AppBarLayout. use it only if you need to
|
||||
* set fitSystemWindows for StatusBar
|
||||
*
|
||||
* @author cginechen
|
||||
* @date 2017-09-20
|
||||
*/
|
||||
|
||||
public class QMUIAppBarLayout extends AppBarLayout implements IWindowInsetLayout {
|
||||
public QMUIAppBarLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public QMUIAppBarLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applySystemWindowInsets19(final Rect insets) {
|
||||
if (ViewCompat.getFitsSystemWindows(this)) {
|
||||
try {
|
||||
Field field = AppBarLayout.class.getDeclaredField("mLastInsets");
|
||||
field.setAccessible(true);
|
||||
field.set(this, new WindowInsetsCompat(null) {
|
||||
@Override
|
||||
public int getSystemWindowInsetTop() {
|
||||
return insets.top;
|
||||
}
|
||||
});
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
View child = getChildAt(i);
|
||||
if (QMUIWindowInsetHelper.jumpDispatch(child)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!QMUIWindowInsetHelper.isHandleContainer(child)) {
|
||||
child.setPadding(insets.left, insets.top, insets.right, insets.bottom);
|
||||
} else {
|
||||
if (child instanceof IWindowInsetLayout) {
|
||||
((IWindowInsetLayout) child).applySystemWindowInsets19(insets);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applySystemWindowInsets21(WindowInsetsCompat insets) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import android.graphics.Rect;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.IntDef;
|
||||
@@ -68,7 +69,7 @@ import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
|
||||
* @date 2017-09-02
|
||||
*/
|
||||
|
||||
public class QMUICollapsingTopBarLayout extends FrameLayout {
|
||||
public class QMUICollapsingTopBarLayout extends FrameLayout implements IWindowInsetLayout {
|
||||
|
||||
private static final int DEFAULT_SCRIM_ANIMATION_DURATION = 600;
|
||||
|
||||
@@ -100,6 +101,7 @@ public class QMUICollapsingTopBarLayout extends FrameLayout {
|
||||
int mCurrentOffset;
|
||||
|
||||
WindowInsetsCompat mLastInsets;
|
||||
Rect mLastInsetRect;
|
||||
|
||||
public QMUICollapsingTopBarLayout(Context context) {
|
||||
this(context, null);
|
||||
@@ -184,13 +186,21 @@ public class QMUICollapsingTopBarLayout extends FrameLayout {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(this,
|
||||
new android.support.v4.view.OnApplyWindowInsetsListener() {
|
||||
@Override
|
||||
public WindowInsetsCompat onApplyWindowInsets(View v,
|
||||
WindowInsetsCompat insets) {
|
||||
return onWindowInsetChanged(insets);
|
||||
public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
|
||||
return setWindowInsets(insets);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private WindowInsetsCompat setWindowInsets(WindowInsetsCompat insets) {
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
if (applySystemWindowInsets21(insets)) {
|
||||
return insets.consumeSystemWindowInsets();
|
||||
}
|
||||
}
|
||||
return insets;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
@@ -222,24 +232,6 @@ public class QMUICollapsingTopBarLayout extends FrameLayout {
|
||||
super.onDetachedFromWindow();
|
||||
}
|
||||
|
||||
WindowInsetsCompat onWindowInsetChanged(final WindowInsetsCompat insets) {
|
||||
WindowInsetsCompat newInsets = null;
|
||||
|
||||
if (ViewCompat.getFitsSystemWindows(this)) {
|
||||
// If we're set to fit system windows, keep the insets
|
||||
newInsets = insets;
|
||||
}
|
||||
|
||||
// If our insets have changed, keep them and invalidate the scroll ranges...
|
||||
if (!QMUILangHelper.objectEquals(mLastInsets, newInsets)) {
|
||||
mLastInsets = newInsets;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
// Consume the insets. This is done so that child views with fitSystemWindows=true do not
|
||||
// get the default padding functionality from View
|
||||
return insets.consumeSystemWindowInsets();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
@@ -260,7 +252,7 @@ public class QMUICollapsingTopBarLayout extends FrameLayout {
|
||||
|
||||
// Now draw the status bar scrim
|
||||
if (mStatusBarScrim != null && mScrimAlpha > 0) {
|
||||
final int topInset = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
|
||||
final int topInset = getWindowInsetTop();
|
||||
if (topInset > 0) {
|
||||
mStatusBarScrim.setBounds(0, -mCurrentOffset, getWidth(),
|
||||
topInset - mCurrentOffset);
|
||||
@@ -270,6 +262,16 @@ public class QMUICollapsingTopBarLayout extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
private int getWindowInsetTop() {
|
||||
if (mLastInsets != null) {
|
||||
return mLastInsets.getSystemWindowInsetTop();
|
||||
}
|
||||
if (mLastInsetRect != null) {
|
||||
return mLastInsetRect.top;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
|
||||
// This is a little weird. Our scrim needs to be behind the Toolbar (if it is present),
|
||||
@@ -354,9 +356,9 @@ public class QMUICollapsingTopBarLayout extends FrameLayout {
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
if (mLastInsets != null) {
|
||||
if (mLastInsets != null || mLastInsetRect != null) {
|
||||
// Shift down any views which are not set to fit system windows
|
||||
final int insetTop = mLastInsets.getSystemWindowInsetTop();
|
||||
final int insetTop = getWindowInsetTop();
|
||||
for (int i = 0, z = getChildCount(); i < z; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (ViewCompat.getFitsSystemWindows(child)) {
|
||||
@@ -511,7 +513,6 @@ public class QMUICollapsingTopBarLayout extends FrameLayout {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param scrimUpdateListener 为 null 则是 removeUpdateListener
|
||||
*/
|
||||
public void setScrimUpdateListener(ValueAnimator.AnimatorUpdateListener scrimUpdateListener) {
|
||||
@@ -523,7 +524,7 @@ public class QMUICollapsingTopBarLayout extends FrameLayout {
|
||||
mScrimAnimator.removeUpdateListener(mScrimUpdateListener);
|
||||
}
|
||||
mScrimUpdateListener = scrimUpdateListener;
|
||||
if(mScrimUpdateListener != null){
|
||||
if (mScrimUpdateListener != null) {
|
||||
mScrimAnimator.addUpdateListener(mScrimUpdateListener);
|
||||
}
|
||||
}
|
||||
@@ -971,7 +972,7 @@ public class QMUICollapsingTopBarLayout extends FrameLayout {
|
||||
}
|
||||
|
||||
// Otherwise we'll use the default computed value
|
||||
final int insetTop = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
|
||||
final int insetTop = getWindowInsetTop();
|
||||
|
||||
final int minHeight = ViewCompat.getMinimumHeight(this);
|
||||
if (minHeight > 0) {
|
||||
@@ -1020,6 +1021,48 @@ public class QMUICollapsingTopBarLayout extends FrameLayout {
|
||||
return new QMUICollapsingTopBarLayout.LayoutParams(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected boolean fitSystemWindows(Rect insets) {
|
||||
return applySystemWindowInsets19(insets);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applySystemWindowInsets19(Rect insets) {
|
||||
Rect newInsets = null;
|
||||
if (ViewCompat.getFitsSystemWindows(this)) {
|
||||
// If we're set to fit system windows, keep the insets
|
||||
newInsets = insets;
|
||||
}
|
||||
|
||||
// If our insets have changed, keep them and invalidate the scroll ranges...
|
||||
if (!QMUILangHelper.objectEquals(mLastInsets, newInsets)) {
|
||||
mLastInsetRect = newInsets;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
// Consume the insets. This is done so that child views with fitSystemWindows=true do not
|
||||
// get the default padding functionality from View
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applySystemWindowInsets21(WindowInsetsCompat insets) {
|
||||
WindowInsetsCompat newInsets = null;
|
||||
|
||||
if (ViewCompat.getFitsSystemWindows(this)) {
|
||||
// If we're set to fit system windows, keep the insets
|
||||
newInsets = insets;
|
||||
}
|
||||
|
||||
// If our insets have changed, keep them and invalidate the scroll ranges...
|
||||
if (!QMUILangHelper.objectEquals(mLastInsets, newInsets)) {
|
||||
mLastInsets = newInsets;
|
||||
requestLayout();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class LayoutParams extends FrameLayout.LayoutParams {
|
||||
|
||||
private static final float DEFAULT_PARALLAX_MULTIPLIER = 0.5f;
|
||||
@@ -1161,7 +1204,7 @@ public class QMUICollapsingTopBarLayout extends FrameLayout {
|
||||
public void onOffsetChanged(AppBarLayout layout, int verticalOffset) {
|
||||
mCurrentOffset = verticalOffset;
|
||||
|
||||
final int insetTop = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
|
||||
final int insetTop = getWindowInsetTop();
|
||||
|
||||
for (int i = 0, z = getChildCount(); i < z; i++) {
|
||||
final View child = getChildAt(i);
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.qmuiteam.qmui.widget;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v4.view.WindowInsetsCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
@@ -56,4 +57,11 @@ public class QMUIWindowInsetLayout extends FrameLayout implements IWindowInsetLa
|
||||
return mQMUIWindowInsetHelper.defaultApplySystemWindowInsets21(this, insets);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
if (ViewCompat.getFitsSystemWindows(this)) {
|
||||
ViewCompat.requestApplyInsets(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
<com.qmuiteam.qmui.widget.QMUIAppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="256dp"
|
||||
android:fitsSystemWindows="true">
|
||||
@@ -40,7 +40,7 @@
|
||||
app:qmui_topbar_bg_color="@color/qmui_config_color_transparent"
|
||||
app:qmui_topbar_need_separator="false"/>
|
||||
</com.qmuiteam.qmui.widget.QMUICollapsingTopBarLayout>
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
</com.qmuiteam.qmui.widget.QMUIAppBarLayout>
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
android:background="?attr/app_content_bg_color"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="@dimen/home_tab_height"/>
|
||||
android:layout_marginBottom="@dimen/home_tab_height"
|
||||
android:fitsSystemWindows="true"/>
|
||||
<com.qmuiteam.qmui.widget.QMUITabSegment
|
||||
android:id="@+id/tabs"
|
||||
android:layout_gravity="bottom"
|
||||
|
||||
Reference in New Issue
Block a user