EditText AdjustResize 强制内容不可见
EditText AdjustResize forcing content out of view
我目前正在开发一个简单的笔记应用程序,用户可以在其中输入标题和笔记内容。我想要实现的是,当用户单击注释内容 (EditText) 时,软键盘出现,只有注释内容 EditText 的大小减小(调整大小),而其他所有内容都保持在相同的位置。
我当前的实现如下所示:
清单:
<activity android:theme="@style/AppTheme"
android:name=".AddActivity"
android:label="@string/add_record"
android:windowSoftInputMode="adjustResize"
android:parentActivityName=".MainActivity"
android:excludeFromRecents="true"/>
XML - 添加 Activity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/add_record"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp">
<EditText
android:id="@+id/title_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/enter_title"
android:inputType="textCapSentences"
android:textColor="@color/fontPrimary"
android:theme="@style/EditTextCustomCursor">
<requestFocus />
</EditText>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/modify_scrollview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fitsSystemWindows="false"
android:isScrollContainer="false"
android:fillViewport="true">
<EditText
android:id="@+id/note_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:ellipsize="end"
android:gravity="top|left"
android:hint="@string/enter_note"
android:inputType="textCapSentences|textMultiLine"
android:paddingLeft="5dp"
android:scrollHorizontally="false"
android:textColor="@color/fontPrimary"
android:theme="@style/EditTextCustomCursor" />
</ScrollView>
</LinearLayout>
Java - 添加 Activity
private int screenHeight;
private int actionBarHeight = 350;
private int keyboardHeight;
...
private void setupListeners() {
final LinearLayout layout = (LinearLayout) findViewById(R.id.add_record);
layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
layout.getWindowVisibleDisplayFrame(r);
screenHeight = layout.getRootView().getHeight();
keyboardHeight = screenHeight - (r.bottom - r.top);
Log.d("Keyboard Size", "Size: " + keyboardHeight);
}
});
KeyboardVisibilityEvent.setEventListener(
AddActivity.this,
new KeyboardVisibilityEventListener() {
@Override
public void onVisibilityChanged(boolean isOpen) {
if (isOpen) {
Log.d("KB", "openKeyboard");
scrollView.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, screenHeight - actionBarHeight - keyboardHeight));
} else {
Log.d("KB", "closeKeyboard");
scrollView.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
}
}
});
}
这是使用键盘库 (https://github.com/yshrsmz/KeyboardVisibilityEvent) 来检测键盘何时打开或关闭。这非常有效,并且高度/布局调整到我想要的样子,但前提是用户单击 EditText 的顶部。如果用户单击 EditText 的底部(如果他们输入了一个长注释),那么整个布局将被向上推,在页面底部留下一个大间隙。
因此,有什么方法可以让用户在 EditText / ScrollView 中的任何位置单击,只调整一个 EditText 的高度,而将另一个 EditText 留在屏幕顶部的适当位置而不推动它和SupportActionBar 看不见?此外,ScrollView 用于实现屏幕右侧的垂直滚动条 - 如果仅使用 EditText 可以实现相同的行为,那么我将完全删除 ScrollView。
编辑 - 添加照片
图1:长笔记内容(笔记内容的底部在scrollView的底部(滚动后才能看到))
图片 2:相同的注释,但单击底部,迫使顶部的 EditText 和 Support ActionBar 离开视图,同时在底部留下一个间隙。
说明:F 突出显示的地方(在图 2 中)是 EditText/ScrollView 的底部,因此您可以看到软键盘顶部和 EditText/ScrollView 底部之间形成的大间隙
期望的行为:单击底部 EditText 中的任意位置应该只调整特定 EditText 的大小以为软键盘腾出空间,并确保此 EditText 位于软键盘上方,以便用户可以在顶部 EditText 时看到他们正在输入的内容始终保持在同一位置。
这是因为您要在滚动视图中添加编辑文本。为什么你甚至需要滚动视图?当键盘 pop-up 导致此行为时,滚动视图有一个转到特定行的 属性。如果你真的想使用滚动视图,然后添加主布局作为滚动视图。在其中添加一个直接子项 aka 线性布局,并在该线性布局中添加所有内容。
我已通过执行以下操作成功解决了大部分问题:
- 移除 ScrollView
- 继承 EditText(接收关闭键盘按钮)
- 添加 height-change 侦听器
- 将滚动条 属性 添加到 EditText
清单:
<activity android:theme="@style/AppTheme"
android:name=".AddActivity"
android:label="@string/add_record"
android:windowSoftInputMode="adjustNothing"
android:parentActivityName=".MainActivity"
android:excludeFromRecents="true"/>
XML - 添加 Activity:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/add_record"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
android:windowSoftInputMode="stateHidden">
<EditText
android:id="@+id/title_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/enter_title"
android:inputType="textCapSentences"
android:textColor="@color/fontPrimary"
android:theme="@style/EditTextCustomCursor">
<requestFocus />
</EditText>
<com.securenotes.ExtendedEditText
android:id="@+id/note_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:ellipsize="end"
android:gravity="top|left"
android:hint="@string/enter_note"
android:inputType="textCapSentences|textMultiLine"
android:lines="50"
android:maxLines="20"
android:minLines="5"
android:paddingLeft="5dp"
android:scrollHorizontally="false"
android:scrollbars="vertical"
android:textColor="@color/fontPrimary"
android:theme="@style/EditTextCustomCursor" />
</LinearLayout>
Java - 添加 Activity:
private Boolean initialStart = true;
private Boolean isOpened = false;
...
private void setupListeners() {
final View activityRootView = getWindow().getDecorView().findViewById(android.R.id.content);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
Log.d("KB", "HeightDiff: " + heightDiff);
if (heightDiff > 100) { // 99% of the time the height diff will be due to a keyboard.
if (!isOpened && initialStart) {
Log.d("KB", "1) openKeyboard");
//Do two things, make the view top visible and the editText smaller
noteEditText.setLines(15);
noteEditText.requestLayout();
initialStart = false;
isOpened = true;
} else if (!isOpened && noteEditText.hasFocus()) {
Log.d("KB", "2) openKeyboard");
//Do two things, make the view top visible and the editText smaller
noteEditText.setLines(15);
noteEditText.requestLayout();
isOpened = true;
}
}
}
});
noteEditText.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("KB", "EditText onClick");
isOpened = false;
}
});
noteEditText.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
Log.d("KB", "closeKeyboard");
noteEditText.setLines(50);
noteEditText.requestLayout();
}
return false;
}
});
}
Java - 子类化的 EditText:
public class ExtendedEditText extends EditText {
public ExtendedEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ExtendedEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ExtendedEditText(Context context) {
super(context);
}
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
dispatchKeyEvent(event);
return false;
}
return super.onKeyPreIme(keyCode, event);
}
}
但是,剩下的一个问题是,如果用户正在滚动 EditText,有时它会将其检测为单击而不是滚动,因此键盘会变得可见并且布局(行数)会发生变化。我查看了 onScrollChangeListener,但这需要 API 23,而我当前的最小值是 15 - 有什么办法可以区分滚动和实际点击 EditText 之间的区别吗?
我目前正在开发一个简单的笔记应用程序,用户可以在其中输入标题和笔记内容。我想要实现的是,当用户单击注释内容 (EditText) 时,软键盘出现,只有注释内容 EditText 的大小减小(调整大小),而其他所有内容都保持在相同的位置。
我当前的实现如下所示:
清单:
<activity android:theme="@style/AppTheme"
android:name=".AddActivity"
android:label="@string/add_record"
android:windowSoftInputMode="adjustResize"
android:parentActivityName=".MainActivity"
android:excludeFromRecents="true"/>
XML - 添加 Activity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/add_record"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp">
<EditText
android:id="@+id/title_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/enter_title"
android:inputType="textCapSentences"
android:textColor="@color/fontPrimary"
android:theme="@style/EditTextCustomCursor">
<requestFocus />
</EditText>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/modify_scrollview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fitsSystemWindows="false"
android:isScrollContainer="false"
android:fillViewport="true">
<EditText
android:id="@+id/note_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:ellipsize="end"
android:gravity="top|left"
android:hint="@string/enter_note"
android:inputType="textCapSentences|textMultiLine"
android:paddingLeft="5dp"
android:scrollHorizontally="false"
android:textColor="@color/fontPrimary"
android:theme="@style/EditTextCustomCursor" />
</ScrollView>
</LinearLayout>
Java - 添加 Activity
private int screenHeight;
private int actionBarHeight = 350;
private int keyboardHeight;
...
private void setupListeners() {
final LinearLayout layout = (LinearLayout) findViewById(R.id.add_record);
layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
layout.getWindowVisibleDisplayFrame(r);
screenHeight = layout.getRootView().getHeight();
keyboardHeight = screenHeight - (r.bottom - r.top);
Log.d("Keyboard Size", "Size: " + keyboardHeight);
}
});
KeyboardVisibilityEvent.setEventListener(
AddActivity.this,
new KeyboardVisibilityEventListener() {
@Override
public void onVisibilityChanged(boolean isOpen) {
if (isOpen) {
Log.d("KB", "openKeyboard");
scrollView.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, screenHeight - actionBarHeight - keyboardHeight));
} else {
Log.d("KB", "closeKeyboard");
scrollView.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
}
}
});
}
这是使用键盘库 (https://github.com/yshrsmz/KeyboardVisibilityEvent) 来检测键盘何时打开或关闭。这非常有效,并且高度/布局调整到我想要的样子,但前提是用户单击 EditText 的顶部。如果用户单击 EditText 的底部(如果他们输入了一个长注释),那么整个布局将被向上推,在页面底部留下一个大间隙。
因此,有什么方法可以让用户在 EditText / ScrollView 中的任何位置单击,只调整一个 EditText 的高度,而将另一个 EditText 留在屏幕顶部的适当位置而不推动它和SupportActionBar 看不见?此外,ScrollView 用于实现屏幕右侧的垂直滚动条 - 如果仅使用 EditText 可以实现相同的行为,那么我将完全删除 ScrollView。
编辑 - 添加照片
图1:长笔记内容(笔记内容的底部在scrollView的底部(滚动后才能看到))
图片 2:相同的注释,但单击底部,迫使顶部的 EditText 和 Support ActionBar 离开视图,同时在底部留下一个间隙。
说明:F 突出显示的地方(在图 2 中)是 EditText/ScrollView 的底部,因此您可以看到软键盘顶部和 EditText/ScrollView 底部之间形成的大间隙
期望的行为:单击底部 EditText 中的任意位置应该只调整特定 EditText 的大小以为软键盘腾出空间,并确保此 EditText 位于软键盘上方,以便用户可以在顶部 EditText 时看到他们正在输入的内容始终保持在同一位置。
这是因为您要在滚动视图中添加编辑文本。为什么你甚至需要滚动视图?当键盘 pop-up 导致此行为时,滚动视图有一个转到特定行的 属性。如果你真的想使用滚动视图,然后添加主布局作为滚动视图。在其中添加一个直接子项 aka 线性布局,并在该线性布局中添加所有内容。
我已通过执行以下操作成功解决了大部分问题:
- 移除 ScrollView
- 继承 EditText(接收关闭键盘按钮)
- 添加 height-change 侦听器
- 将滚动条 属性 添加到 EditText
清单:
<activity android:theme="@style/AppTheme"
android:name=".AddActivity"
android:label="@string/add_record"
android:windowSoftInputMode="adjustNothing"
android:parentActivityName=".MainActivity"
android:excludeFromRecents="true"/>
XML - 添加 Activity:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/add_record"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
android:windowSoftInputMode="stateHidden">
<EditText
android:id="@+id/title_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/enter_title"
android:inputType="textCapSentences"
android:textColor="@color/fontPrimary"
android:theme="@style/EditTextCustomCursor">
<requestFocus />
</EditText>
<com.securenotes.ExtendedEditText
android:id="@+id/note_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:ellipsize="end"
android:gravity="top|left"
android:hint="@string/enter_note"
android:inputType="textCapSentences|textMultiLine"
android:lines="50"
android:maxLines="20"
android:minLines="5"
android:paddingLeft="5dp"
android:scrollHorizontally="false"
android:scrollbars="vertical"
android:textColor="@color/fontPrimary"
android:theme="@style/EditTextCustomCursor" />
</LinearLayout>
Java - 添加 Activity:
private Boolean initialStart = true;
private Boolean isOpened = false;
...
private void setupListeners() {
final View activityRootView = getWindow().getDecorView().findViewById(android.R.id.content);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
Log.d("KB", "HeightDiff: " + heightDiff);
if (heightDiff > 100) { // 99% of the time the height diff will be due to a keyboard.
if (!isOpened && initialStart) {
Log.d("KB", "1) openKeyboard");
//Do two things, make the view top visible and the editText smaller
noteEditText.setLines(15);
noteEditText.requestLayout();
initialStart = false;
isOpened = true;
} else if (!isOpened && noteEditText.hasFocus()) {
Log.d("KB", "2) openKeyboard");
//Do two things, make the view top visible and the editText smaller
noteEditText.setLines(15);
noteEditText.requestLayout();
isOpened = true;
}
}
}
});
noteEditText.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("KB", "EditText onClick");
isOpened = false;
}
});
noteEditText.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
Log.d("KB", "closeKeyboard");
noteEditText.setLines(50);
noteEditText.requestLayout();
}
return false;
}
});
}
Java - 子类化的 EditText:
public class ExtendedEditText extends EditText {
public ExtendedEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ExtendedEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ExtendedEditText(Context context) {
super(context);
}
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
dispatchKeyEvent(event);
return false;
}
return super.onKeyPreIme(keyCode, event);
}
}
但是,剩下的一个问题是,如果用户正在滚动 EditText,有时它会将其检测为单击而不是滚动,因此键盘会变得可见并且布局(行数)会发生变化。我查看了 onScrollChangeListener,但这需要 API 23,而我当前的最小值是 15 - 有什么办法可以区分滚动和实际点击 EditText 之间的区别吗?