Android WindowsOfInputMode=";“调整大小”;不使用半透明操作/导航栏
我对新安卓KitKat(4.4)中的半透明actionbar/navbar和Android WindowsOfInputMode=";“调整大小”;不使用半透明操作/导航栏,android,resize,statusbar,android-4.4-kitkat,window-soft-input-mode,Android,Resize,Statusbar,Android 4.4 Kitkat,Window Soft Input Mode,我对新安卓KitKat(4.4)中的半透明actionbar/navbar和WindowsofInputMode=“adjustResize”有问题 通常,将InputMode更改为adjustResize,当显示键盘时,应用程序应该自行调整大小,但在这里它不会!如果删除透明效果的线条,则调整大小有效 因此,如果键盘可见,我的ListView就在它下面,我无法访问最后几项(仅通过手动隐藏键盘) AndroidManifest.xml: <?xml version="1.0&quo
WindowsofInputMode=“adjustResize”
有问题
通常,将InputMode更改为adjustResize
,当显示键盘时,应用程序应该自行调整大小,但在这里它不会!如果删除透明效果的线条,则调整大小有效
因此,如果键盘可见,我的ListView
就在它下面,我无法访问最后几项(仅通过手动隐藏键盘)
AndroidManifest.xml
:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="XYZ"
android:versionCode="23"
android:versionName="0.1" >
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.XYZStyle" >
<activity
android:name="XYZ"
android:label="@string/app_name"
android:windowSoftInputMode="adjustResize" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
values-v19/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.XYZStyle" parent="@style/Theme.AppCompat.Light">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
</resources>
真的
真的
fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/listView_contacts"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:divider="@null"
android:dividerHeight="0dp"
android:drawSelectorOnTop="true"
android:fastScrollAlwaysVisible="true"
android:fastScrollEnabled="true"
android:paddingBottom="@dimen/navigationbar__height" >
</ListView>
</RelativeLayout>
有什么解决方法吗?您缺少以下属性:
android:fitsSystemWindows="true"
在片段.xml布局的根RelativeLayout
中
更新:
fun View?.fitSystemWindowsAndAdjustResize() = this?.let { view ->
ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
view.fitsSystemWindows = true
val bottom = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
WindowInsetsCompat
.Builder()
.setInsets(
WindowInsetsCompat.Type.systemBars(),
Insets.of(0, 0, 0, bottom)
)
.build()
.apply {
ViewCompat.onApplyWindowInsets(v, this)
}
}
}
rootView.fitSystemWindowsAndAdjustResize()
去年,克里斯·班恩(Chris Bane)进行了一次有趣的演讲,详细解释了这一过程:
有一个相关的bug报告。我已经找到了一种解决方法,通过有限的测试,它似乎可以做到不产生任何影响。使用下面的逻辑添加根
视图组的自定义实现(我几乎总是使用FrameLayout
,所以这就是我测试的内容)。然后,使用此自定义布局代替根布局,并确保设置了android:fitsystemwindows=“true”
。然后,如果需要,您可以在布局后随时调用getInsets()
(例如,添加一个OnPreDrawListener
)来调整布局的其余部分以考虑系统插入
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import org.jetbrains.annotations.NotNull;
/**
* @author Kevin
* Date Created: 3/7/14
*
* https://code.google.com/p/android/issues/detail?id=63777
*
* When using a translucent status bar on API 19+, the window will not
* resize to make room for input methods (i.e.
* {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} and
* {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_PAN} are
* ignored).
*
* To work around this; override {@link #fitSystemWindows(android.graphics.Rect)},
* capture and override the system insets, and then call through to FrameLayout's
* implementation.
*
* For reasons yet unknown, modifying the bottom inset causes this workaround to
* fail. Modifying the top, left, and right insets works as expected.
*/
public final class CustomInsetsFrameLayout extends FrameLayout {
private int[] mInsets = new int[4];
public CustomInsetsFrameLayout(Context context) {
super(context);
}
public CustomInsetsFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public final int[] getInsets() {
return mInsets;
}
@Override
protected final boolean fitSystemWindows(@NotNull Rect insets) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// Intentionally do not modify the bottom inset. For some reason,
// if the bottom inset is modified, window resizing stops working.
// TODO: Figure out why.
mInsets[0] = insets.left;
mInsets[1] = insets.top;
mInsets[2] = insets.right;
insets.left = 0;
insets.top = 0;
insets.right = 0;
}
return super.fitSystemWindows(insets);
}
}
由于fitSystemWindow
s已被弃用,请参考下面的答案以完成解决方法。我也遇到了同样的问题,
我的活动有一个作为根视图的滚动视图,在半透明状态栏激活的情况下,当键盘显示时,它无法正确调整大小。。。因此,屏幕不会滚动隐藏输入视图
解决方案:
将所有内容(布局和活动逻辑)移动到新片段中。
然后将活动更改为仅包含此片段。现在一切正常
这是活动的布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/contentView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" />
@kcopock的答案非常有用,但fitSystemWindows在API级别20中被弃用
因此,由于API 20(KITKAT_WATCH),您应该覆盖onApplyWindowInsets
@Override
public final WindowInsets onApplyWindowInsets(WindowInsets insets) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0,
insets.getSystemWindowInsetBottom()));
} else {
return insets;
}
}
基于Joseph Johnson在
在活动中的setContentView()
之后的onCreate()
中调用此函数
androIDBUG5497解决方案。辅助性(this)代码>
与原来的替换返回有点不同(r.bottom-r.top)代码>带返回右下角代码>在ComputeUsableLight()中
出于某种原因,我必须将我的活动fitsystemwindows
属性设置为false
这个变通办法救了我。这对我很有效。希望能帮助你
实现类是:
public class AndroidBug5497Workaround {
// For more information, see https://code.google.com/p/android/issues/detail?id=5497
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
public static void assistActivity (Activity activity) {
new AndroidBug5497Workaround(activity);
}
private View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;
private AndroidBug5497Workaround(Activity activity) {
FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
mChildOfContent = content.getChildAt(0);
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
possiblyResizeChildOfContent();
}
});
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
}
private void possiblyResizeChildOfContent() {
int usableHeightNow = computeUsableHeight();
if (usableHeightNow != usableHeightPrevious) {
int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
if (heightDifference > (usableHeightSansKeyboard/4)) {
// keyboard probably just became visible
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
} else {
// keyboard probably just became hidden
frameLayoutParams.height = usableHeightSansKeyboard;
}
mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
private int computeUsableHeight() {
Rect r = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(r);
return r.bottom;
}
}
AndroidBug5497Workaround.java小心内存泄漏。需要下面的代码
getViewTreeObserver().removeOnGlobalLayoutListener(listener);
我的示例使用RxJava,在活动生命周期中的onPause()时自动调用RemoveOnGlobalYoutListener()
public class MyActivity extends RxAppCompatActivity {
// ...
protected void onStart(){
super.onStart();
TRSoftKeyboardVisibility
.changes(this) // activity
.compose(this.<TRSoftKeyboardVisibility.ChangeEvent>bindUntilEvent(ActivityEvent.PAUSE))
.subscribe(keyboardEvent -> {
FrameLayout content = (FrameLayout) findViewById(android.R.id.content);
View firstChildView = content.getChildAt(0);
firstChildView.getLayoutParams().height = keyboardEvent.viewHeight();
firstChildView.requestLayout();
// keyboardEvent.isVisible = keyboard visible or not
// keyboardEvent.keyboardHeight = keyboard height
// keyboardEvent.viewHeight = fullWindowHeight - keyboardHeight
});
//...
}
package commonlib.rxjava.keyboard;
import android.app.Activity;
import android.view.View;
import android.widget.FrameLayout;
import kr.ohlab.android.util.Assert;
import rx.Observable;
public class TRSoftKeyboardVisibility {
public static Observable<ChangeEvent> changes(Activity activity) {
Assert.notNull(activity, "activity == null");
FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
View childOfContent = content.getChildAt(0);
return Observable.create(
new TRSoftKeyboardVisibilityEventOnSubscribe(childOfContent));
}
public static final class ChangeEvent {
private final int keyboardHeight;
private final boolean visible;
private final int viewHeight;
public static ChangeEvent create(boolean visible, int keyboardHeight,
int windowDisplayHeight) {
return new ChangeEvent(visible, keyboardHeight, windowDisplayHeight);
}
private ChangeEvent(boolean visible, int keyboardHeight, int viewHeight) {
this.keyboardHeight = keyboardHeight;
this.visible = visible;
this.viewHeight = viewHeight;
}
public int keyboardHeight() {
return keyboardHeight;
}
public boolean isVisible() {
return this.visible;
}
public int viewHeight() {
return viewHeight;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ChangeEvent)) return false;
ChangeEvent that = (ChangeEvent) o;
if (keyboardHeight != that.keyboardHeight) return false;
if (visible != that.visible) return false;
return viewHeight == that.viewHeight;
}
@Override
public int hashCode() {
int result = keyboardHeight;
result = 31 * result + (visible ? 1 : 0);
result = 31 * result + viewHeight;
return result;
}
@Override
public String toString() {
return "ChangeEvent{" +
"keyboardHeight=" + keyboardHeight +
", visible=" + visible +
", viewHeight=" + viewHeight +
'}';
}
}
}
package commonlib.rxjava.keyboard;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;
import kr.ohlab.android.util.Assert;
import rx.Observable;
import rx.Subscriber;
import rx.android.MainThreadSubscription;
import timber.log.Timber;
public class TRSoftKeyboardVisibilityEventOnSubscribe
implements Observable.OnSubscribe<TRSoftKeyboardVisibility.ChangeEvent> {
private final View mTopView;
private int mLastVisibleDecorViewHeight;
private final Rect mWindowVisibleDisplayFrame = new Rect();
public TRSoftKeyboardVisibilityEventOnSubscribe(View topView) {
mTopView = topView;
}
private int computeWindowFrameHeight() {
mTopView.getWindowVisibleDisplayFrame(mWindowVisibleDisplayFrame);
return (mWindowVisibleDisplayFrame.bottom - mWindowVisibleDisplayFrame.top);
}
private TRSoftKeyboardVisibility.ChangeEvent checkKeyboardVisibility() {
int windowFrameHeightNow = computeWindowFrameHeight();
TRSoftKeyboardVisibility.ChangeEvent event = null;
if (windowFrameHeightNow != mLastVisibleDecorViewHeight) {
int mTopViewHeight = mTopView.getHeight();
int heightDiff = mTopViewHeight - windowFrameHeightNow;
Timber.e("XXX heightDiff=" + heightDiff);
if (heightDiff > (mTopViewHeight / 4)) {
event = TRSoftKeyboardVisibility.ChangeEvent.create(true, heightDiff, windowFrameHeightNow);
} else {
event = TRSoftKeyboardVisibility.ChangeEvent.create(false, 0, windowFrameHeightNow);
}
mLastVisibleDecorViewHeight = windowFrameHeightNow;
return event;
}
return null;
}
public void call(final Subscriber<? super TRSoftKeyboardVisibility.ChangeEvent> subscriber) {
Assert.checkUiThread();
final ViewTreeObserver.OnGlobalLayoutListener listener =
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
TRSoftKeyboardVisibility.ChangeEvent event = checkKeyboardVisibility();
if( event == null)
return;
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(event);
}
}
};
mTopView.getViewTreeObserver().addOnGlobalLayoutListener(listener);
subscriber.add(new MainThreadSubscription() {
@Override
protected void onUnsubscribe() {
mTopView.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
}
});
}
}
公共类MyActivity扩展了RXAppCompative{
// ...
受保护的void onStart(){
super.onStart();
TRSoftKeyboardVisibility
.changes(this)//活动
.compose(this.bindUntilEvent(ActivityEvent.PAUSE))
.订阅(键盘事件->{
FrameLayout content=(FrameLayout)findviewbyd(android.R.id.content);
View firstChildView=content.getChildAt(0);
firstChildView.getLayoutParams().height=keyboardEvent.viewHeight();
firstChildView.requestLayout();
//keyboardEvent.isVisible=键盘是否可见
//keyboardEvent.keyboardHeight=键盘高度
//keyboardEvent.viewHeight=完整窗口高度-键盘高度
});
//...
}
包commonlib.rxjava.keyboard;
导入android.app.Activity;
导入android.view.view;
导入android.widget.FrameLayout;
导入kr.ohlab.android.util.Assert;
进口接收。可观察;
公共类TRSoftKeyboardVisibility{
公共静态可观察变化(活动){
Assert.notNull(活动,“活动==null”);
FrameLayout content=(FrameLayout)activity.findviewbyd(android.R.id.content);
View childOfContent=content.getChildAt(0);
返回可观察的。创建(
新TrSoftKeyboard VisibilityEventsSubscribe(内容的孩子));
}
公共静态最终类更改事件{
私人最终整型键盘高度;
私有最终布尔值可见;
私人最终取景高度;
公共静态ChangeEvent创建(布尔可见,整型键盘高度,
int窗口显示高度){
返回新的ChangeEvent(可见、键盘高度、windowDisplayHeight);
}
私有ChangeEvent(布尔可见、int键盘高度、int视图高度){
此参数。键盘高度=键盘高度;
可见的;可见的;
this.viewHeight=viewHeight;
}
公共int键盘高度(){
返回键盘高度;
}
公共布尔值可见(){
返回这个.visible;
}
公共int viewHeight(){
返回视图高度;
}
@凌驾
公共布尔等于(对象o){
如果(this==o)返回true;
如果(!(o instanceof ChangeEvent))返回false;
ChangeEvent,它=(ChangeEvent)o;
如果(keyboardHeight!=that.keyboardHeight)返回false;
如果(visible!=that.visible)返回false;
return viewHeight==that.viewHeight;
}
@凌驾
公共整数hashCod
<com.dhna.widget.ZeroInsetsFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:background="@color/white">
<!-- your xml code -->
</ZeroInsetsFrameLayout>
public class CustomRelativeLayout extends RelativeLayout {
private int[] mInsets = new int[4];
public CustomRelativeLayout(Context context) {
super(context);
}
public CustomRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public final WindowInsets onApplyWindowInsets(WindowInsets insets) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
mInsets[0] = insets.getSystemWindowInsetLeft();
mInsets[1] = insets.getSystemWindowInsetTop();
mInsets[2] = insets.getSystemWindowInsetRight();
return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0,
insets.getSystemWindowInsetBottom()));
} else {
return insets;
}
}
}
<com.blah.blah.CustomRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
</com.blah.blah.CustomRelativeLayout>
ViewCompat.setOnApplyWindowInsetsListener(container) { view, insets ->
insets.replaceSystemWindowInsets(0, 0, 0, insets.systemWindowInsetBottom).apply {
ViewCompat.onApplyWindowInsets(view, this)
}
}
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
/>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<!-- Your xml -->
</RelativeLayout>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView("Your Activity");
setAdjustScreen();
}
protected void setAdjustScreen(){
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
/*android:windowSoftInputMode="adjustPan|adjustResize"*/
}
<activity
android:name="Your Activity"
android:windowSoftInputMode="adjustPan|adjustResize"
android:screenOrientation="portrait"></activity>
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:layout_height="match_parent" android:layout_width="match_parent"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
app:popupTheme="@style/AppTheme.PopupOverlay"
android:background="?attr/colorPrimary"
android:id="@+id/toolbar"/>
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_main2"/>
</android.support.design.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.v7.widget.RecyclerView
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_marginTop="30dp"
android:layout_marginBottom="30dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:id="@+id/post_msg_recyclerview">
</android.support.v7.widget.RecyclerView>
<EditText
android:layout_width="match_parent"
android:layout_height="50dp"
app:layout_constraintBottom_toBottomOf="parent"
android:background="@color/colorPrimary"
/>
</android.support.constraint.ConstraintLayout>
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(linearLayoutManager);
Adapter adapter1=new Adapter(arrayList);
recyclerView.setAdapter(adapter1);
<androidx.constraintlayout.widget.ConstraintLayout
android:fitsSystemWindows="true">
<androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.appbar.CollapsingToolbarLayout/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView>
<Editext/>
<androidx.core.widget.NestedScrollView/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
android:fitsSystemWindows="true"
fun View?.fitSystemWindowsAndAdjustResize() = this?.let { view ->
ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
view.fitsSystemWindows = true
val bottom = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
WindowInsetsCompat
.Builder()
.setInsets(
WindowInsetsCompat.Type.systemBars(),
Insets.of(0, 0, 0, bottom)
)
.build()
.apply {
ViewCompat.onApplyWindowInsets(v, this)
}
}
}
rootView.fitSystemWindowsAndAdjustResize()