Umano SlidingPanel 中状态栏下方的滑动布局
Sliding layout below status bar in Umano SlidingPanel
我已经使用 https://github.com/umano/AndroidSlidingUpPanel 实现了 UmanoSlidingPanel。一切正常,除了我的滑动面板在展开时,滑动内容 (sliding_view) 在状态栏下方。我怎样才能避免这种情况?我尝试删除
<item name="android:windowTranslucentStatus">true</item>
来自 styles.xml 但这也使主要内容的状态栏变得不透明。有什么办法可以解决这个问题?
<com.sothree.slidinguppanel.SlidingUpPanelLayout xmlns:sothree="http://schemas.android.com/apk/res-auto"
android:id="@+id/sliding_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
sothree:umanoDragView="@+id/firstPanelDragArea"
sothree:umanoPanelHeight="@dimen/bottom_panel_height"
sothree:umanoShadowHeight="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar" />
<FrameLayout
android:id="@+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<!-- SLIDING LAYOUT -->
<LinearLayout
android:id="@+id/firstPanelDragArea"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/sliding_view" />
</LinearLayout>
styles.xml
<style name="AppTheme" parent="@style/Theme.AppCompat">
<item name="windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="windowNoTitle">true</item>
</style>
编辑
public void onPanelSlide(View panel, float slideOffset) {
if (slideOffset > 0.5 && !flagTransparent) {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
flagTransparent = true;
Log.i(TAG, "onPanelSlide, offset " + slideOffset);
} else if (slideOffset < 0.5 && flagTransparent){
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
flagTransparent = false;
Log.i(TAG, "onPanelSlide, offset " + slideOffset);
}
在父布局中尝试 android:fitsSystemWindows="true"
。那应该可以解决您的问题。
我过去实施的另一个解决方案是,在包含 slidingUpPanel 的 activity 中,您可以使用半透明状态栏 (API >= 19) 来设置样式:
<item name="android:windowTranslucentStatus">true</item>
然后在 onPanelSlide
回调中,您可以修改 slidingUpPanel 的填充,逐步添加直到面板完全向上。在那一刻,添加的额外填充量应该是状态栏尺寸。
1) 看看下面我创建的Gist
文件 sliding_up_activity.xml
可能是包含您的向上滑动面板视图的 activity 布局。
您应该在其中设置 android:fitsSystemWindows="true"
,以便正确插入任何子项,而不会落后于操作栏或导航栏。
文件sliding_view.xml
可能是您向上滑动的视图。
您不需要在任何面板回调中执行任何其他操作。
您可以安全地删除半透明样式和 onPanelSlide()
中的代码。这应该会导致滑动面板正确插入,这样永远不会落后于状态或导航栏。
或者,如果您没有相同的体系结构,您可以忘记 sliding_up_activity.xml
并在 CoordinatorLayout
中设置 android:fitsSystemWindows="true"
,而不是在 sliding_view.xml
中。
2) 我们讨论的第二件事是使状态栏半透明,让向上滑动的面板落在状态栏后面,然后平滑地添加填充以正确插入内容。
为此,设置 android:fitsSystemWindows="false"
或将其从您的向上滑动面板的任何可能父项中删除。
然后在 onPanelSlide
你可以做这样的事情
if (slideOffset >= ANCHOR_POINT) {
// adjust the span of the offset
float offset = (slideOffset - ANCHOR_POINT) / (1 - ANCHOR_POINT);
// the padding top will be the base original padding plus a percentage of the status
// bar height
float paddingTop = mSlidePanelBasePadding + offset * mStatusBarInset;
// apply the padding to the header container
mContainer.setPadding(0, (int) paddingTop, 0, 0);
}
其中:
mSlidePanelBasePadding
将是您向上滑动面板的初始填充
mStatusBarInset
将是状态栏高度。
这应该会在您的 slidingUp 面板超过锚点时逐渐向其添加填充。
你可以这样获取状态栏高度:
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
希望对您有所帮助。
通过更改 SlidingUpPanelLayout.java 的 onMeasure 方法找到了问题的另一种解决方案。为将来发布代码 readers.Need 添加 4 行代码。
SlidingPanelLayout.java
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException("Width must have an exact value or MATCH_PARENT");
} else if (heightMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException("Height must have an exact value or MATCH_PARENT");
}
final int childCount = getChildCount();
if (childCount != 2) {
throw new IllegalStateException("Sliding up panel layout must have exactly 2 children!");
}
mMainView = getChildAt(0);
mSlideableView = getChildAt(1);
if (mDragView == null) {
setDragView(mSlideableView);
}
// If the sliding panel is not visible, then put the whole view in the hidden state
if (mSlideableView.getVisibility() != VISIBLE) {
mSlideState = PanelState.HIDDEN;
}
int layoutHeight = heightSize - getPaddingTop() - getPaddingBottom();
int layoutWidth = widthSize - getPaddingLeft() - getPaddingRight();
// First pass. Measure based on child LayoutParams width/height.
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
// We always measure the sliding panel in order to know it's height (needed for show panel)
if (child.getVisibility() == GONE && i == 0) {
continue;
}
int height = layoutHeight;
int width = layoutWidth;
if (child == mMainView) {
if (!mOverlayContent && mSlideState != PanelState.HIDDEN) {
height -= mPanelHeight;
}
width -= lp.leftMargin + lp.rightMargin;
} else if (child == mSlideableView) {
// The slideable view should be aware of its top margin.
// See https://github.com/umano/AndroidSlidingUpPanel/issues/412.
// height -= lp.topMargin;.
// START OF CODE CHANGES
if (height < SCREEN_HEIGHT) { //SCREEN_HEIGHT = 900
height = height - MARGIN_BOTTOM; //MARGIN_BOTTOM = 8
} else {
height = height - getStatusBarHeight();
}
// END OF CODE CHANGES
}
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
我已经使用 https://github.com/umano/AndroidSlidingUpPanel 实现了 UmanoSlidingPanel。一切正常,除了我的滑动面板在展开时,滑动内容 (sliding_view) 在状态栏下方。我怎样才能避免这种情况?我尝试删除
<item name="android:windowTranslucentStatus">true</item>
来自 styles.xml 但这也使主要内容的状态栏变得不透明。有什么办法可以解决这个问题?
<com.sothree.slidinguppanel.SlidingUpPanelLayout xmlns:sothree="http://schemas.android.com/apk/res-auto"
android:id="@+id/sliding_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
sothree:umanoDragView="@+id/firstPanelDragArea"
sothree:umanoPanelHeight="@dimen/bottom_panel_height"
sothree:umanoShadowHeight="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar" />
<FrameLayout
android:id="@+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<!-- SLIDING LAYOUT -->
<LinearLayout
android:id="@+id/firstPanelDragArea"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/sliding_view" />
</LinearLayout>
styles.xml
<style name="AppTheme" parent="@style/Theme.AppCompat">
<item name="windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="windowNoTitle">true</item>
</style>
编辑
public void onPanelSlide(View panel, float slideOffset) {
if (slideOffset > 0.5 && !flagTransparent) {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
flagTransparent = true;
Log.i(TAG, "onPanelSlide, offset " + slideOffset);
} else if (slideOffset < 0.5 && flagTransparent){
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
flagTransparent = false;
Log.i(TAG, "onPanelSlide, offset " + slideOffset);
}
在父布局中尝试 android:fitsSystemWindows="true"
。那应该可以解决您的问题。
我过去实施的另一个解决方案是,在包含 slidingUpPanel 的 activity 中,您可以使用半透明状态栏 (API >= 19) 来设置样式:
<item name="android:windowTranslucentStatus">true</item>
然后在 onPanelSlide
回调中,您可以修改 slidingUpPanel 的填充,逐步添加直到面板完全向上。在那一刻,添加的额外填充量应该是状态栏尺寸。
1) 看看下面我创建的Gist
文件 sliding_up_activity.xml
可能是包含您的向上滑动面板视图的 activity 布局。
您应该在其中设置 android:fitsSystemWindows="true"
,以便正确插入任何子项,而不会落后于操作栏或导航栏。
文件sliding_view.xml
可能是您向上滑动的视图。
您不需要在任何面板回调中执行任何其他操作。
您可以安全地删除半透明样式和 onPanelSlide()
中的代码。这应该会导致滑动面板正确插入,这样永远不会落后于状态或导航栏。
或者,如果您没有相同的体系结构,您可以忘记 sliding_up_activity.xml
并在 CoordinatorLayout
中设置 android:fitsSystemWindows="true"
,而不是在 sliding_view.xml
中。
2) 我们讨论的第二件事是使状态栏半透明,让向上滑动的面板落在状态栏后面,然后平滑地添加填充以正确插入内容。
为此,设置 android:fitsSystemWindows="false"
或将其从您的向上滑动面板的任何可能父项中删除。
然后在 onPanelSlide
你可以做这样的事情
if (slideOffset >= ANCHOR_POINT) {
// adjust the span of the offset
float offset = (slideOffset - ANCHOR_POINT) / (1 - ANCHOR_POINT);
// the padding top will be the base original padding plus a percentage of the status
// bar height
float paddingTop = mSlidePanelBasePadding + offset * mStatusBarInset;
// apply the padding to the header container
mContainer.setPadding(0, (int) paddingTop, 0, 0);
}
其中:
mSlidePanelBasePadding
将是您向上滑动面板的初始填充mStatusBarInset
将是状态栏高度。
这应该会在您的 slidingUp 面板超过锚点时逐渐向其添加填充。
你可以这样获取状态栏高度:
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
希望对您有所帮助。
通过更改 SlidingUpPanelLayout.java 的 onMeasure 方法找到了问题的另一种解决方案。为将来发布代码 readers.Need 添加 4 行代码。
SlidingPanelLayout.java
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException("Width must have an exact value or MATCH_PARENT");
} else if (heightMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException("Height must have an exact value or MATCH_PARENT");
}
final int childCount = getChildCount();
if (childCount != 2) {
throw new IllegalStateException("Sliding up panel layout must have exactly 2 children!");
}
mMainView = getChildAt(0);
mSlideableView = getChildAt(1);
if (mDragView == null) {
setDragView(mSlideableView);
}
// If the sliding panel is not visible, then put the whole view in the hidden state
if (mSlideableView.getVisibility() != VISIBLE) {
mSlideState = PanelState.HIDDEN;
}
int layoutHeight = heightSize - getPaddingTop() - getPaddingBottom();
int layoutWidth = widthSize - getPaddingLeft() - getPaddingRight();
// First pass. Measure based on child LayoutParams width/height.
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
// We always measure the sliding panel in order to know it's height (needed for show panel)
if (child.getVisibility() == GONE && i == 0) {
continue;
}
int height = layoutHeight;
int width = layoutWidth;
if (child == mMainView) {
if (!mOverlayContent && mSlideState != PanelState.HIDDEN) {
height -= mPanelHeight;
}
width -= lp.leftMargin + lp.rightMargin;
} else if (child == mSlideableView) {
// The slideable view should be aware of its top margin.
// See https://github.com/umano/AndroidSlidingUpPanel/issues/412.
// height -= lp.topMargin;.
// START OF CODE CHANGES
if (height < SCREEN_HEIGHT) { //SCREEN_HEIGHT = 900
height = height - MARGIN_BOTTOM; //MARGIN_BOTTOM = 8
} else {
height = height - getStatusBarHeight();
}
// END OF CODE CHANGES
}
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}