我有一组带有控件的活动(EditText,Spinner等),其中一个EditText有一个自定义键盘。这是我的XML的样子
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/masterRelativeLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ScrollView
android:id="@+id/mainScrollview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true" >
<LinearLayout
android:id="@+id/childLinearLayout"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<!-- Many EditText's, Spinners here -->
</LinearLayout>
</ScrollView>
<android.inputmethodservice.KeyboardView
android:id="@+id/myKeyboardView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:keyPreviewLayout ="@layout/kbdpreview"
android:layout_alignParentBottom="true"
android:visibility="gone" />
</RelativeLayout>
请注意,键盘视图底部对齐,因此它显示在屏幕底部。
自定义键盘被隐藏并显示在特定的EditText上,如下所示:
当触摸活动中的特定EditText时,将调用这些方法。
private OnTouchListener m_onTouchListenerNotationText = new OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
if (v == m_notationText)
{
// Hide the default keyboard
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
m_notationText.onTouchEvent(event);
m_customKeyboard.showCustomKeyboard(v);
AdjustScrollView();
return true; // Done with the event
}
return false;
}
};
每当屏幕上出现自定义键盘时,它都会隐藏我视图中的某些控件。但是,Android框架不知道此键盘正在显示,因此scrollview无法调整。控件仍隐藏在自定义键盘后面。因此,我在自定义键盘中实现了一个回调,当键盘可见时会调用它。
// This listener is in showCustomKeyboard(...) function
// Set a static variable m_height and tell the activity to adjust the scrollview after keyboard becomes VISIBLE
mKeyboardView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
{
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout()
{
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
if (currentapiVersion >= android.os.Build.VERSION_CODES.JELLY_BEAN)
{
mKeyboardView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
else
{
mKeyboardView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
m_height = mKeyboardView.getHeight();
Log.d(TAG, "Custom Keyboard now visible, height = " + m_height);
mHostActivity.AdjustScrollView();
}
});
// This listener is in hideCustomKeyboard(...) function
// Set a static variable m_height and tell the activity to adjust the scrollview after keyboard becomes HIDDEN
view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
{
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout()
{
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
if (currentapiVersion >= android.os.Build.VERSION_CODES.JELLY_BEAN)
{
view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
else
{
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
m_height = 0;
Log.d(TAG, "Custom Keyboard now hidden");
mHostActivity.AdjustScrollView();
}
});
最后,滚动视图调整如下:
public synchronized void AdjustScrollView()
{
RelativeLayout rl = (RelativeLayout) findViewById(R.id.masterRelativeLayout);
int masterHeight = rl.getHeight();
Log.d(TAG, "Scrollview master relative layout height = " + masterHeight);
LinearLayout ll = (LinearLayout) findViewById(R.id.childLinearLayout);
int childHeight = ll.getHeight();
Log.d(TAG, "Scrollview child linear layout height = " + childHeight);
ScrollView scrollView = (ScrollView) findViewById(R.id.mainScrollview);
if (masterHeight - childHeight - m_customKeyboard.m_height <= 0)
{
// Need to adjust scrollview's height
scrollView.getLayoutParams().height = masterHeight - m_customKeyboard.m_height;
Log.d(TAG, "Setting scrollview.layoutparams.height = " + (masterHeight - m_customKeyboard.m_height));
}
else if (m_customKeyboard.m_height == 0)
{
// Need to adjust scrollview's height to full screen
scrollView.getLayoutParams().height = childHeight;
Log.d(TAG, "Setting scrollview.layoutparams.height = " + childHeight);
}
}
AndroidManifest.xml对此活动有以下行:
android:windowSoftInputMode="stateAlwaysHidden|stateUnchanged|adjustResize"
这主要有效,有两个问题:
问题1:当我长按显示自定义键盘的EditText时,有时会出现竞争条件,即默认键盘 AND 自定义键盘都会暂时显示,然后默认键盘消失(因为我将其隐藏在m_onTouchListenerNotationText中)。但是在这个时候,AdjustScrollView的计算搞砸了,因为现在,主相对布局高度非常小(总高度 - 自定义键盘高度 - 默认键盘高度)。所以上面的scrollview高度计算是错误的。现在,scrollview被限制在屏幕顶部的一个非常小的区域,然后是空白区域,然后是我底部的自定义键盘。我通过在EditText的触摸侦听器中添加对AdjustScrollView的调用来解决这个问题(因此,只要发生这种情况,用户就可以单击该微小视图,触摸侦听器将调整scrollview)。这种解决方法是不可取的,因为它使得长按无用(我希望用户能够长按以显示剪切/复制/粘贴等的默认系统菜单)。需要额外触摸的解决方法使得系统菜单消失。
问题2:如果隐藏了自定义键盘,则滚动视图不会再次占用整个屏幕尺寸。屏幕的底部部分(由自定义键盘占用)保持空白,滚动视图仅位于屏幕的顶部。
答案 0 :(得分:0)
我找到的唯一解决方案是使用键盘hide-show
检测,如下例所示:
https://stackoverflow.com/a/7423586/1979882
概念是将背景布局覆盖为您的自定义和度量。
public class VLinearLayoutKeyboardListener extends LinearLayout {
public interface IKeyboardChanged {
void onKeyboardShown(int actualHeight, int proposedheight);
void onKeyboardHidden(int actualHeight, int proposedheight);
}
private ArrayList<IKeyboardChanged> keyboardListener = new ArrayList<IKeyboardChanged>();
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public VLinearLayoutKeyboardListener(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VLinearLayoutKeyboardListener(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VLinearLayoutKeyboardListener(Context context) {
super(context);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public VLinearLayoutKeyboardListener(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
// TODO Auto-generated constructor stub
}
public void addKeyboardStateChangedListener(IKeyboardChanged listener) {
keyboardListener.add(listener);
}
public void removeKeyboardStateChangedListener(IKeyboardChanged listener) {
keyboardListener.remove(listener);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);
final int actualHeight = getHeight();
if (actualHeight > proposedheight) {
notifyKeyboardShown(actualHeight, proposedheight);
} else if (actualHeight < proposedheight) {
notifyKeyboardHidden(actualHeight, proposedheight);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void notifyKeyboardHidden(int actualHeight, int proposedheight) {
for (IKeyboardChanged listener : keyboardListener) {
listener.onKeyboardHidden(actualHeight, proposedheight);
}
}
private void notifyKeyboardShown(int actualHeight, int proposedheight) {
for (IKeyboardChanged listener : keyboardListener) {
listener.onKeyboardShown(actualHeight, proposedheight);
}
}
}
在活动中
public class mAct extends Activity implements IKeyboardChanged {
private VLinearLayoutKeyboardListener vllkl;
onCreate(){
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
}
@Override
public void onDestroy() {
super.onDestroy();
vllkl.removeKeyboardStateChangedListener(this);
}
@Override
public void onKeyboardShown(int actualHeight, int proposedheight) {
//actualHeight - old value
//proposedheight - new value
Log.d(TAG,"onKeyboardShown(): [" + actualHeight + ", " + proposedheight + "]");
//here you can setup Views heights
}
@Override
public void onKeyboardHidden(int actualHeight, int proposedheight) {
//actualHeight - old value
//proposedheight - new value
Log.d(TAG,"onKeyboardHidden(): [" + actualHeight + ", " + proposedheight + "]");
//here you can setup Views heights
}
}
XML中的
<?xml version="1.0" encoding="utf-8"?>
<your.package.name.VLinearLayoutKeyboardListener xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:orientation="vertical"
android:id="@+id/root">
....
</your.package.name.VLinearLayoutKeyboardListener >