【发布时间】:2016-01-31 16:32:43
【问题描述】:
我有一个带有一堆控件(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 框架不知道正在显示此键盘,因此滚动视图不会调整。控件仍然隐藏在自定义键盘后面。因此,我在自定义键盘中实现了一个回调,该回调在键盘可见时被调用。
// 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的计算就搞砸了,因为现在master的相对布局高度很小(总高度-自定义键盘高度-默认键盘高度)。所以上面的scrollview高度计算是错误的。滚动视图现在被限制在屏幕顶部的一个非常小的区域,然后是空白区域,然后是底部的自定义键盘。我通过在 EditText 的触摸侦听器中添加对 AdjustScrollView 的调用来解决此问题(因此,无论何时发生这种情况,用户都可以单击该小视图,并且触摸侦听器将调整滚动视图)。这种解决方法是不可取的,因为它会使长按无用(我希望用户能够长按以显示剪切/复制/粘贴等默认系统菜单)。需要额外触摸的解决方法使这个系统菜单消失了。
问题2:如果自定义键盘被隐藏,滚动视图不会再次占用整个屏幕大小。被自定义键盘占据的屏幕底部保持空白,滚动视图仅在屏幕顶部。
【问题讨论】:
-
你试过 android:windowSoftInputMode="adjustPan"
标签: android keyboard scrollview