dmo*_*mon 54 android illegalargumentexception viewgroup viewroot
我有一个ListView,里面有一些可聚焦的组件(主要是EditText
s).是的,我知道这不是完全推荐的,但总的来说,几乎所有东西都工作正常,重点放在必须去的地方(我需要进行一些调整代码).无论如何,我的问题是,当用手指滚动列表然后在显示IME键盘时突然使用轨迹球时,存在一种奇怪的竞争条件.有些东西必须超出范围并得到回收,此时该offsetRectBetweenParentAndChild()
方法必须启动并抛出IllegalArgumentException
.
问题是这个异常被抛出我可以插入try/catch的任何块之外(据我所知).所以这个问题有两个有效的解决方案:
ViewGroup
这些方法,但这两种offset*
方法被标记为final.堆栈跟踪:
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): FATAL EXCEPTION: main
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): java.lang.IllegalArgumentException: parameter must be a descendant of this view
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): at android.view.ViewGroup.offsetRectBetweenParentAndChild(ViewGroup.java:2633)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): at android.view.ViewGroup.offsetDescendantRectToMyCoords(ViewGroup.java:2570)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): at android.view.ViewRoot.scrollToRectOrFocus(ViewRoot.java:1624)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): at android.view.ViewRoot.draw(ViewRoot.java:1357)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): at android.view.ViewRoot.performTraversals(ViewRoot.java:1258)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): at android.view.ViewRoot.handleMessage(ViewRoot.java:1859)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): at android.os.Handler.dispatchMessage(Handler.java:99)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): at android.os.Looper.loop(Looper.java:130)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): at android.app.ActivityThread.main(ActivityThread.java:3683)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): at java.lang.reflect.Method.invokeNative(Native Method)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): at java.lang.reflect.Method.invoke(Method.java:507)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
08-17 18:23:09.825: ERROR/AndroidRuntime(1608): at dalvik.system.NativeStart.main(Native Method)
Run Code Online (Sandbox Code Playgroud)
Bru*_*uce 31
很抱歉告诉你,我发现我之前的答案不是解决这个问题的最完美方式.
所以我试试这个:
将一个ScrollListener附加到Activity,当listView开始滚动时,清除当前焦点.
protected class MyScrollListener implements OnScrollListener {
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// do nothing
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (SCROLL_STATE_TOUCH_SCROLL == scrollState) {
View currentFocus = getCurrentFocus();
if (currentFocus != null) {
currentFocus.clearFocus();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
ndo*_*ori 29
虽然布鲁斯的答案确实解决了这个问题,但它却以非常残酷的方式解决了这个问题,因为一旦我们做了滚动,它就会清除每个视图的焦点.
它处理问题的症状,但它没有解决实际原因.
如何重现问题:
您的EditText具有焦点并且键盘已打开,然后滚动直到EditText离开屏幕,并且它没有被回收到现在显示的新EditText.
让我们首先理解为什么会出现这个问题:
众所周知,ListView会回收其视图并再次使用它们,但有时它不需要立即使用已离开屏幕的视图,以便将其保留以备将来使用,并且因为它不再需要再显示将分离它导致view.mParent为null.但是键盘需要知道如何将输入传递给它,它通过选择聚焦视图或精确的EditText来实现.
所以问题是我们有一个EditText谁有焦点,但突然没有父,所以我们得到一个"参数必须是这个视图的后代"错误.这是有道理的.
通过使用滚动侦听器,我们会导致更多问题.
解决方案:
我们需要听一个事件,告诉我们什么时候视图已经进入侧堆并且不再附加,幸运的是ListView公开了这个事件.
listView.setRecyclerListener(new AbsListView.RecyclerListener() {
@Override
public void onMovedToScrapHeap(View view) {
if ( view.hasFocus()){
view.clearFocus(); //we can put it inside the second if as well, but it makes sense to do it to all scraped views
//Optional: also hide keyboard in that case
if ( view instanceof EditText) {
InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
}
});
Run Code Online (Sandbox Code Playgroud)
Bru*_*uce 24
试试这个
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//abandon current focus
View currentFocus = ((Activity)mContext).getCurrentFocus();
if (currentFocus != null) {
currentFocus.clearFocus();
}
// other code
}
Run Code Online (Sandbox Code Playgroud)
编辑:
另见:更好的解决方案
dmo*_*mon 10
对于它的价值(或者偶然发现了什么),我已经放弃了此活动的ListView方法.除了随机崩溃之外,几乎不可能正确地获得焦点行为而不设置windowSoftInputMode="adjustPan"
打开一堆其他的蠕虫.相反,我只是去了一个"简单"的ScrollView,它一直很好用.
小智 8
我稍微调整了布鲁斯的答案.
我需要adjustResize
在我的活动中而不是adjustpan
在我尝试时再次发生错误.
我换ScrollView
了<android.support.v4.widget.NestedScrollView
,现在工作正常.希望这有助于某人!
我有最简单但不是很好的解决方案。只需扩展 NestedScrollView 并覆盖 onSizeChanged 方法,添加一个 try catch 块。
public class FixFocusErrorNestedScrollView extends NestedScrollView {
public FixFocusErrorNestedScrollView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
try {
super.onSizeChanged(w, h, oldw, oldh);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Run Code Online (Sandbox Code Playgroud)
就我而言,我有两个层视图,顶层是 listView,底层是 NestedScrollView。切换图层时发生错误。焦点由 ListeView 项目(按钮)获取。
所以我不能让按钮失去焦点。那么最好的解决方案是扩展 NestedScrollView。
我面临着同样的问题,找到了这个解决方案-以OnGroupCollapseListener/OnGroupExpandListener
和OnScrollListener
为ExpandableListView
我明确focuse和隐藏被迫键盘.另外,不要忘记manifest
为您的活动设置windowSoftInputMode="adjustPan"
:
expListView.setOnGroupCollapseListener(new OnGroupCollapseListener() {
@Override
public void onGroupCollapse(int groupPosition) {
InputMethodManager inputManager = (InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (getWindow().getCurrentFocus() != null) {
inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
getCurrentFocus().clearFocus();
}
}
});
expListView.setOnGroupExpandListener(new OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
InputMethodManager inputManager = (InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (getWindow().getCurrentFocus() != null) {
inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
getCurrentFocus().clearFocus();
}
}
});
expListView.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
InputMethodManager inputManager = (InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (getCurrentFocus() != null) {
inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
getCurrentFocus().clearFocus();
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}
});
Run Code Online (Sandbox Code Playgroud)
我不知道确切OnGroupExpandListener
需要与否,它可能毫无用处.
在可扩展列表视图的情况下,如果您的子项目具有编辑文本,那么您需要在可扩展列表视图的后代之前更改可聚焦性
expandableListView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
33099 次 |
最近记录: |