android removeview 焦点发生变化,Android问题记录02_点击RecyclerView headView 中的editText等控件导致焦点变化,recyclerView莫名滑动...

1.问题现象

点击recyclerView headView 中的EditText时recycleView 莫名自动滑动

827fd1195cc6

image

布局代码

主布局

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:fitsSystemWindows="true"

android:orientation="vertical">

android:layout_width="match_parent"

android:layout_height="56dp">

android:id="@+id/toolbar"

android:layout_width="match_parent"

android:layout_height="match_parent"

app:theme="@style/ToolbarTheme" />

android:id="@+id/tv_title"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:layout_centerInParent="true"

android:gravity="center"

android:text="@string/title_new_card"

android:textColor="@color/white"

android:textSize="20sp" />

android:id="@+id/iv_back"

android:layout_width="36dp"

android:layout_height="36dp"

android:layout_centerVertical="true"

android:layout_marginLeft="10dp"

android:padding="7dp"

android:src="@drawable/nav_btn_back" />

android:id="@+id/recyclerView"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@color/white" />

headView布局

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:background="@color/white"

android:focusable="true"

android:id="@+id/fdfsdf"

android:focusableInTouchMode="true"

android:orientation="vertical"

android:paddingLeft="16dp"

android:paddingRight="16dp">

android:layout_width="match_parent"

android:layout_height="wrap_content">

android:id="@+id/et_card_name"

android:layout_width="match_parent"

android:layout_height="48dp"

android:layout_centerVertical="true"

android:background="@null"

android:gravity="center_vertical"

android:hint="@string/hint_edit_card_name"

android:paddingRight="2dp"

android:maxLines="1"

android:textColor="@color/text_black"

android:textColorHint="@color/text_hint"

android:textSize="@dimen/font_small_3" />

android:id="@+id/cardNameUnderLine"

android:layout_width="match_parent"

android:layout_height="1dp"

android:background="@color/divide_line" />

android:layout_width="match_parent"

android:layout_height="wrap_content">

android:id="@+id/iv_card_id_copy"

android:layout_width="24dp"

android:layout_height="24dp"

android:layout_alignParentRight="true"

android:layout_centerVertical="true"

android:src="@drawable/btn_copy" />

android:id="@+id/et_card_id"

android:layout_width="match_parent"

android:layout_height="48dp"

android:layout_centerVertical="true"

android:layout_toLeftOf="@id/iv_card_id_copy"

android:background="@null"

android:gravity="center_vertical"

android:hint="@string/hint_edit_card_id"

android:paddingRight="2dp"

android:maxLines="1"

android:textColor="@color/text_black"

android:textColorHint="@color/text_hint"

android:textSize="@dimen/font_small_3" />

android:id="@+id/cardIdUnderLine"

android:layout_width="match_parent"

android:layout_height="1dp"

android:background="@color/divide_line" />

android:id="@+id/layout_card_type"

android:layout_width="match_parent"

android:layout_height="48dp"

android:gravity="center_vertical"

android:orientation="horizontal">

android:id="@+id/icon_card_type"

android:layout_width="24dp"

android:layout_height="24dp"

android:src="@drawable/btn_cards" />

android:id="@+id/tv_card_type"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_marginLeft="16dp"

android:layout_weight="1"

android:text="@string/str_card_type"

android:textColor="@color/text_black"

android:textSize="@dimen/font_small_3" />

android:layout_width="24dp"

android:layout_height="24dp"

android:scaleType="center"

android:src="@drawable/btn_up" />

android:layout_width="match_parent"

android:layout_height="1dp"

android:background="@color/divide_line" />

android:layout_width="match_parent"

android:layout_height="12dp" />

2.问题原因

在ViewGroup中 源码

private void addViewInner(View child, int index, LayoutParams params,

boolean preventRequestLayout) {

if (mTransition != null) {

// Don't prevent other add transitions from completing, but cancel remove

// transitions to let them complete the process before we add to the container

mTransition.cancel(LayoutTransition.DISAPPEARING);

}

if (child.getParent() != null) {

throw new IllegalStateException("The specified child already has a parent. " +

"You must call removeView() on the child's parent first.");

}

if (mTransition != null) {

mTransition.addChild(this, child);

}

if (!checkLayoutParams(params)) {

params = generateLayoutParams(params);

}

if (preventRequestLayout) {

child.mLayoutParams = params;

} else {

child.setLayoutParams(params);

}

if (index < 0) {

index = mChildrenCount;

}

addInArray(child, index);

// tell our children

if (preventRequestLayout) {

child.assignParent(this);

} else {

child.mParent = this;

}

//look here!!!!!!!!!!!!!!!! 看这!!!!!!!!!!!

if (child.hasFocus()) {

requestChildFocus(child, child.findFocus());

}

AttachInfo ai = mAttachInfo;

if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {

boolean lastKeepOn = ai.mKeepScreenOn;

ai.mKeepScreenOn = false;

child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));

if (ai.mKeepScreenOn) {

needGlobalAttributesUpdate(true);

}

ai.mKeepScreenOn = lastKeepOn;

}

**if (child.isLayoutDirectionInherited()) {

child.resetRtlProperties();

}**

dispatchViewAdded(child);

if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {

mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;

}

if (child.hasTransientState()) {

childHasTransientStateChanged(child, true);

}

if (child.getVisibility() != View.GONE) {

notifySubtreeAccessibilityStateChangedIfNeeded();

}

if (mTransientIndices != null) {

final int transientCount = mTransientIndices.size();

for (int i = 0; i < transientCount; ++i) {

final int oldIndex = mTransientIndices.get(i);

if (index <= oldIndex) {

mTransientIndices.set(i, oldIndex + 1);

}

}

}

if (mCurrentDragStartEvent != null && child.getVisibility() == VISIBLE) {

notifyChildOfDragStart(child);

}

}

在recyclerView 中

@Override

public void requestChildFocus(View child, View focused) {

if (!mLayout.onRequestChildFocus(this, mState, child, focused) && focused != null) {

mTempRect.set(0, 0, focused.getWidth(), focused.getHeight());

// get item decor offsets w/o refreshing. If they are invalid, there will be another

// layout pass to fix them, then it is LayoutManager's responsibility to keep focused

// View in viewport.

final ViewGroup.LayoutParams focusedLayoutParams = focused.getLayoutParams();

if (focusedLayoutParams instanceof LayoutParams) {

// if focused child has item decors, use them. Otherwise, ignore.

final LayoutParams lp = (LayoutParams) focusedLayoutParams;

if (!lp.mInsetsDirty) {

final Rect insets = lp.mDecorInsets;

mTempRect.left -= insets.left;

mTempRect.right += insets.right;

mTempRect.top -= insets.top;

mTempRect.bottom += insets.bottom;

}

}

offsetDescendantRectToMyCoords(focused, mTempRect);

offsetRectIntoDescendantCoords(child, mTempRect);

//look here!!!!!! 看这儿!!!!!!

requestChildRectangleOnScreen(child, mTempRect, !mFirstLayoutComplete);}

super.requestChildFocus(child, focused);

}

@Override

public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) {

return mLayout.requestChildRectangleOnScreen(this, child, rect, immediate);

}

requestChildRectangleOnScreen 在recyclerView 中的具体实现

/**

* Requests that the given child of the RecyclerView be positioned onto the screen. This

* method can be called for both unfocusable and focusable child views. For unfocusable

* child views, focusedChildVisible is typically true in which case, layout manager

* makes the child view visible only if the currently focused child stays in-bounds of RV.

* @param parent The parent RecyclerView.

* @param child The direct child making the request.

* @param rect The rectangle in the child's coordinates the child

* wishes to be on the screen.

* @param immediate True to forbid animated or delayed scrolling,

* false otherwise

* @param focusedChildVisible Whether the currently focused view must stay visible.

* @return Whether the group scrolled to handle the operation

*/

public boolean requestChildRectangleOnScreen(RecyclerView parent, View child, Rect rect,

boolean immediate,

boolean focusedChildVisible) {

int[] scrollAmount = getChildRectangleOnScreenScrollAmount(parent, child, rect,

immediate);

int dx = scrollAmount[0];

int dy = scrollAmount[1];

//here 滚动!!! 粗暴点 屏蔽这一段就不滚动了

if (!focusedChildVisible || isFocusedChildVisibleAfterScrolling(parent, dx, dy)) {

if (dx != 0 || dy != 0) {

if (immediate) {

parent.scrollBy(dx, dy);

} else {

parent.smoothScrollBy(dx, dy);

}

return true;

}

}

return false;

}

3.解决办法

自定义layoutManager

/**

* 为了解决recycle人View上添加的headView 中的EditText等控件获取了焦点导致RecyclerView 莫名滚动

*/

class FoucsLinearLayoutManager extends LinearLayoutManager {

public FoucsLinearLayoutManager(Context context) {

super(context);

}

public FoucsLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {

super(context, orientation, reverseLayout);

}

public FoucsLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {

super(context, attrs, defStyleAttr, defStyleRes);

}

/**

*   public boolean requestChildRectangleOnScreen (View child, Rect rectangle, boolean immediate)

*

*   当组里的某个子视图需要被定位在屏幕的某个矩形范围时,调用此方法。重载此方法的ViewGroup可确认以下几点:

*

*   * 子项目将是组里的直系子项

*   * 矩形将在子项目的坐标体系中

*   重载此方法的ViewGroup应该支持以下几点:

*   * 若矩形已经是可见的,则没有东西会改变

*   * 为使矩形区域全部可见,视图将可以被滚动显示

*   参数

*   child 发出请求的子视图

*   rectangle 子项目坐标系内的矩形,即此子项目希望在屏幕上的定位

*   immediate 设为true,则禁止动画和平滑移动滚动条

*

*   返回值

*   进行了滚动操作的这个组(group),是否处理此操作。

*

* @param parent

* @param child

* @param rect

* @param immediate

* @return

*/

@Override

public boolean requestChildRectangleOnScreen(RecyclerView parent, View child, Rect rect, boolean immediate) {

//这里的child 是整个HeadView 而不是某个具体的editText

LogUtil.e("requestChildRectangleOnScreen()====> chlild==" + child.getId() + "parent==" + parent.getId());

return false;

}

@Override

public boolean requestChildRectangleOnScreen(RecyclerView parent, View child, Rect rect, boolean immediate, boolean focusedChildVisible) {

//这里的child 是整个HeadView 而不是某个具体的editText

LogUtil.e("requestChildRectangleOnScreen( focusedChildVisible=)====> chlild==" + child.getId() + "parent==" + parent.getId());

return false;

}

}

替换掉原来的LInearLayoutManager

mRecyclerView = findViewById(view, R.id.recyclerView);

mRecyclerView.setLayoutManager(new FoucsLinearLayoutManager(getContext()));

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值