List of usage examples for android.view View requestFocus
public final boolean requestFocus()
From source file:com.datarita.ultimatecamera.turu.views.TwoWayView.java
private void layoutChildren() { if (getWidth() == 0 || getHeight() == 0) { return;/*from www. ja v a 2s .c o m*/ } final boolean blockLayoutRequests = mBlockLayoutRequests; if (!blockLayoutRequests) { mBlockLayoutRequests = true; } else { return; } try { invalidate(); if (mAdapter == null) { resetState(); return; } final int start = (mIsVertical ? getPaddingTop() : getPaddingLeft()); final int end = (mIsVertical ? getHeight() - getPaddingBottom() : getWidth() - getPaddingRight()); int childCount = getChildCount(); int index = 0; int delta = 0; View focusLayoutRestoreView = null; View selected = null; View oldSelected = null; View newSelected = null; View oldFirstChild = null; switch (mLayoutMode) { case LAYOUT_SET_SELECTION: index = mNextSelectedPosition - mFirstPosition; if (index >= 0 && index < childCount) { newSelected = getChildAt(index); } break; case LAYOUT_FORCE_TOP: case LAYOUT_FORCE_BOTTOM: case LAYOUT_SPECIFIC: case LAYOUT_SYNC: break; case LAYOUT_MOVE_SELECTION: default: // Remember the previously selected view index = mSelectedPosition - mFirstPosition; if (index >= 0 && index < childCount) { oldSelected = getChildAt(index); } // Remember the previous first child oldFirstChild = getChildAt(0); if (mNextSelectedPosition >= 0) { delta = mNextSelectedPosition - mSelectedPosition; } // Caution: newSelected might be null newSelected = getChildAt(index + delta); } final boolean dataChanged = mDataChanged; if (dataChanged) { handleDataChanged(); } // Handle the empty set by removing all views that are visible // and calling it a day if (mItemCount == 0) { resetState(); return; } else if (mItemCount != mAdapter.getCount()) { throw new IllegalStateException("The content of the mAdapter has changed but " + "TwoWayView did not receive a notification. Make sure the content of " + "your mAdapter is not modified from a background thread, but only " + "from the UI thread. [in TwoWayView(" + getId() + ", " + getClass() + ") with Adapter(" + mAdapter.getClass() + ")]"); } setSelectedPositionInt(mNextSelectedPosition); // Reset the focus restoration View focusLayoutRestoreDirectChild = null; // Pull all children into the RecycleBin. // These views will be reused if possible final int firstPosition = mFirstPosition; final RecycleBin recycleBin = mRecycler; if (dataChanged) { for (int i = 0; i < childCount; i++) { recycleBin.addScrapView(getChildAt(i), firstPosition + i); } } else { recycleBin.fillActiveViews(childCount, firstPosition); } // Take focus back to us temporarily to avoid the eventual // call to clear focus when removing the focused child below // from messing things up when ViewAncestor assigns focus back // to someone else. final View focusedChild = getFocusedChild(); if (focusedChild != null) { // We can remember the focused view to restore after relayout if the // data hasn't changed, or if the focused position is a header or footer. if (!dataChanged) { focusLayoutRestoreDirectChild = focusedChild; // Remember the specific view that had focus focusLayoutRestoreView = findFocus(); if (focusLayoutRestoreView != null) { // Tell it we are going to mess with it focusLayoutRestoreView.onStartTemporaryDetach(); } } requestFocus(); } // FIXME: We need a way to save current accessibility focus here // so that it can be restored after we re-attach the children on each // layout round. detachAllViewsFromParent(); switch (mLayoutMode) { case LAYOUT_SET_SELECTION: if (newSelected != null) { final int newSelectedStart = (mIsVertical ? newSelected.getTop() : newSelected.getLeft()); selected = fillFromSelection(newSelectedStart, start, end); } else { selected = fillFromMiddle(start, end); } break; case LAYOUT_SYNC: selected = fillSpecific(mSyncPosition, mSpecificStart); break; case LAYOUT_FORCE_BOTTOM: selected = fillBefore(mItemCount - 1, end); adjustViewsStartOrEnd(); break; case LAYOUT_FORCE_TOP: mFirstPosition = 0; selected = fillFromOffset(start); adjustViewsStartOrEnd(); break; case LAYOUT_SPECIFIC: selected = fillSpecific(reconcileSelectedPosition(), mSpecificStart); break; case LAYOUT_MOVE_SELECTION: selected = moveSelection(oldSelected, newSelected, delta, start, end); break; default: if (childCount == 0) { final int position = lookForSelectablePosition(0); setSelectedPositionInt(position); selected = fillFromOffset(start); } else { if (mSelectedPosition >= 0 && mSelectedPosition < mItemCount) { int offset = start; if (oldSelected != null) { offset = (mIsVertical ? oldSelected.getTop() : oldSelected.getLeft()); } selected = fillSpecific(mSelectedPosition, offset); } else if (mFirstPosition < mItemCount) { int offset = start; if (oldFirstChild != null) { offset = (mIsVertical ? oldFirstChild.getTop() : oldFirstChild.getLeft()); } selected = fillSpecific(mFirstPosition, offset); } else { selected = fillSpecific(0, start); } } break; } recycleBin.scrapActiveViews(); if (selected != null) { if (mItemsCanFocus && hasFocus() && !selected.hasFocus()) { final boolean focusWasTaken = (selected == focusLayoutRestoreDirectChild && focusLayoutRestoreView != null && focusLayoutRestoreView.requestFocus()) || selected.requestFocus(); if (!focusWasTaken) { // Selected item didn't take focus, fine, but still want // to make sure something else outside of the selected view // has focus final View focused = getFocusedChild(); if (focused != null) { focused.clearFocus(); } positionSelector(INVALID_POSITION, selected); } else { selected.setSelected(false); mSelectorRect.setEmpty(); } } else { positionSelector(INVALID_POSITION, selected); } mSelectedStart = (mIsVertical ? selected.getTop() : selected.getLeft()); } else { if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_DRAGGING) { View child = getChildAt(mMotionPosition - mFirstPosition); if (child != null) { positionSelector(mMotionPosition, child); } } else { mSelectedStart = 0; mSelectorRect.setEmpty(); } // Even if there is not selected position, we may need to restore // focus (i.e. something focusable in touch mode) if (hasFocus() && focusLayoutRestoreView != null) { focusLayoutRestoreView.requestFocus(); } } // Tell focus view we are done mucking with it, if it is still in // our view hierarchy. if (focusLayoutRestoreView != null && focusLayoutRestoreView.getWindowToken() != null) { focusLayoutRestoreView.onFinishTemporaryDetach(); } mLayoutMode = LAYOUT_NORMAL; mDataChanged = false; mNeedSync = false; setNextSelectedPositionInt(mSelectedPosition); if (mItemCount > 0) { checkSelectionChanged(); } invokeOnItemScrollListener(); } finally { if (!blockLayoutRequests) { mBlockLayoutRequests = false; mDataChanged = false; } } }
From source file:com.boutline.sports.helpers.TwoWayView.java
private void layoutChildren() { if (getWidth() == 0 || getHeight() == 0) { return;/* w w w . ja v a 2 s . c o m*/ } final boolean blockLayoutRequests = mBlockLayoutRequests; if (!blockLayoutRequests) { mBlockLayoutRequests = true; } else { return; } try { invalidate(); if (mAdapter == null) { resetState(); return; } final int start = getStartEdge(); final int end = getEndEdge(); int childCount = getChildCount(); int index = 0; int delta = 0; View focusLayoutRestoreView = null; View selected = null; View oldSelected = null; View newSelected = null; View oldFirstChild = null; switch (mLayoutMode) { case LAYOUT_SET_SELECTION: index = mNextSelectedPosition - mFirstPosition; if (index >= 0 && index < childCount) { newSelected = getChildAt(index); } break; case LAYOUT_FORCE_TOP: case LAYOUT_FORCE_BOTTOM: case LAYOUT_SPECIFIC: case LAYOUT_SYNC: break; case LAYOUT_MOVE_SELECTION: default: // Remember the previously selected view index = mSelectedPosition - mFirstPosition; if (index >= 0 && index < childCount) { oldSelected = getChildAt(index); } // Remember the previous first child oldFirstChild = getChildAt(0); if (mNextSelectedPosition >= 0) { delta = mNextSelectedPosition - mSelectedPosition; } // Caution: newSelected might be null newSelected = getChildAt(index + delta); } final boolean dataChanged = mDataChanged; if (dataChanged) { handleDataChanged(); } // Handle the empty set by removing all views that are visible // and calling it a day if (mItemCount == 0) { resetState(); return; } else if (mItemCount != mAdapter.getCount()) { throw new IllegalStateException("The content of the adapter has changed but " + "TwoWayView did not receive a notification. Make sure the content of " + "your adapter is not modified from a background thread, but only " + "from the UI thread. [in TwoWayView(" + getId() + ", " + getClass() + ") with Adapter(" + mAdapter.getClass() + ")]"); } setSelectedPositionInt(mNextSelectedPosition); // Reset the focus restoration View focusLayoutRestoreDirectChild = null; // Pull all children into the RecycleBin. // These views will be reused if possible final int firstPosition = mFirstPosition; final RecycleBin recycleBin = mRecycler; if (dataChanged) { for (int i = 0; i < childCount; i++) { recycleBin.addScrapView(getChildAt(i), firstPosition + i); } } else { recycleBin.fillActiveViews(childCount, firstPosition); } // Take focus back to us temporarily to avoid the eventual // call to clear focus when removing the focused child below // from messing things up when ViewAncestor assigns focus back // to someone else. final View focusedChild = getFocusedChild(); if (focusedChild != null) { // We can remember the focused view to restore after relayout if the // data hasn't changed, or if the focused position is a header or footer. if (!dataChanged) { focusLayoutRestoreDirectChild = focusedChild; // Remember the specific view that had focus focusLayoutRestoreView = findFocus(); if (focusLayoutRestoreView != null) { // Tell it we are going to mess with it focusLayoutRestoreView.onStartTemporaryDetach(); } } requestFocus(); } // FIXME: We need a way to save current accessibility focus here // so that it can be restored after we re-attach the children on each // layout round. detachAllViewsFromParent(); switch (mLayoutMode) { case LAYOUT_SET_SELECTION: if (newSelected != null) { final int newSelectedStart = (mIsVertical ? newSelected.getTop() : newSelected.getLeft()); selected = fillFromSelection(newSelectedStart, start, end); } else { selected = fillFromMiddle(start, end); } break; case LAYOUT_SYNC: selected = fillSpecific(mSyncPosition, mSpecificStart); break; case LAYOUT_FORCE_BOTTOM: selected = fillBefore(mItemCount - 1, end); adjustViewsStartOrEnd(); break; case LAYOUT_FORCE_TOP: mFirstPosition = 0; selected = fillFromOffset(start); adjustViewsStartOrEnd(); break; case LAYOUT_SPECIFIC: selected = fillSpecific(reconcileSelectedPosition(), mSpecificStart); break; case LAYOUT_MOVE_SELECTION: selected = moveSelection(oldSelected, newSelected, delta, start, end); break; default: if (childCount == 0) { final int position = lookForSelectablePosition(0); setSelectedPositionInt(position); selected = fillFromOffset(start); } else { if (mSelectedPosition >= 0 && mSelectedPosition < mItemCount) { int offset = start; if (oldSelected != null) { offset = (mIsVertical ? oldSelected.getTop() : oldSelected.getLeft()); } selected = fillSpecific(mSelectedPosition, offset); } else if (mFirstPosition < mItemCount) { int offset = start; if (oldFirstChild != null) { offset = (mIsVertical ? oldFirstChild.getTop() : oldFirstChild.getLeft()); } selected = fillSpecific(mFirstPosition, offset); } else { selected = fillSpecific(0, start); } } break; } recycleBin.scrapActiveViews(); if (selected != null) { if (mItemsCanFocus && hasFocus() && !selected.hasFocus()) { final boolean focusWasTaken = (selected == focusLayoutRestoreDirectChild && focusLayoutRestoreView != null && focusLayoutRestoreView.requestFocus()) || selected.requestFocus(); if (!focusWasTaken) { // Selected item didn't take focus, fine, but still want // to make sure something else outside of the selected view // has focus final View focused = getFocusedChild(); if (focused != null) { focused.clearFocus(); } positionSelector(INVALID_POSITION, selected); } else { selected.setSelected(false); mSelectorRect.setEmpty(); } } else { positionSelector(INVALID_POSITION, selected); } mSelectedStart = (mIsVertical ? selected.getTop() : selected.getLeft()); } else { if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_DRAGGING) { View child = getChildAt(mMotionPosition - mFirstPosition); if (child != null) { positionSelector(mMotionPosition, child); } } else { mSelectedStart = 0; mSelectorRect.setEmpty(); } // Even if there is not selected position, we may need to restore // focus (i.e. something focusable in touch mode) if (hasFocus() && focusLayoutRestoreView != null) { focusLayoutRestoreView.requestFocus(); } } // Tell focus view we are done mucking with it, if it is still in // our view hierarchy. if (focusLayoutRestoreView != null && focusLayoutRestoreView.getWindowToken() != null) { focusLayoutRestoreView.onFinishTemporaryDetach(); } mLayoutMode = LAYOUT_NORMAL; mDataChanged = false; mNeedSync = false; setNextSelectedPositionInt(mSelectedPosition); if (mItemCount > 0) { checkSelectionChanged(); } invokeOnItemScrollListener(); } finally { if (!blockLayoutRequests) { mBlockLayoutRequests = false; mDataChanged = false; } } }
From source file:com.aliasapps.seq.scroller.TwoWayView.java
private void layoutChildren() { if (getWidth() == 0 || getHeight() == 0) { return;/* w w w. j av a 2 s . co m*/ } final boolean blockLayoutRequests = mBlockLayoutRequests; if (!blockLayoutRequests) { mBlockLayoutRequests = true; } else { return; } try { invalidate(); if (mAdapter == null) { resetState(); return; } final int start = (mIsVertical ? getPaddingTop() : getPaddingLeft()); final int end = (mIsVertical ? getHeight() - getPaddingBottom() : getWidth() - getPaddingRight()); int childCount = getChildCount(); int index = 0; int delta = 0; View focusLayoutRestoreView = null; View selected = null; View oldSelected = null; View newSelected = null; View oldFirstChild = null; switch (mLayoutMode) { case LAYOUT_SET_SELECTION: index = mNextSelectedPosition - mFirstPosition; if (index >= 0 && index < childCount) { newSelected = getChildAt(index); } break; case LAYOUT_FORCE_TOP: case LAYOUT_FORCE_BOTTOM: case LAYOUT_SPECIFIC: case LAYOUT_SYNC: break; case LAYOUT_MOVE_SELECTION: default: // Remember the previously selected view index = mSelectedPosition - mFirstPosition; if (index >= 0 && index < childCount) { oldSelected = getChildAt(index); } // Remember the previous first child oldFirstChild = getChildAt(0); if (mNextSelectedPosition >= 0) { delta = mNextSelectedPosition - mSelectedPosition; } // Caution: newSelected might be null newSelected = getChildAt(index + delta); } final boolean dataChanged = mDataChanged; if (dataChanged) { handleDataChanged(); } // Handle the empty set by removing all views that are visible // and calling it a day if (mItemCount == 0) { resetState(); return; } else if (mItemCount != mAdapter.getCount()) { throw new IllegalStateException("The content of the adapter has changed but " + "TwoWayView did not receive a notification. Make sure the content of " + "your adapter is not modified from a background thread, but only " + "from the UI thread. [in TwoWayView(" + getId() + ", " + getClass() + ") with Adapter(" + mAdapter.getClass() + ")]"); } setSelectedPositionInt(mNextSelectedPosition); // Reset the focus restoration View focusLayoutRestoreDirectChild = null; // Pull all children into the RecycleBin. // These views will be reused if possible final int firstPosition = mFirstPosition; final RecycleBin recycleBin = mRecycler; if (dataChanged) { for (int i = 0; i < childCount; i++) { recycleBin.addScrapView(getChildAt(i), firstPosition + i); } } else { recycleBin.fillActiveViews(childCount, firstPosition); } // Take focus back to us temporarily to avoid the eventual // call to clear focus when removing the focused child below // from messing things up when ViewAncestor assigns focus back // to someone else. final View focusedChild = getFocusedChild(); if (focusedChild != null) { // We can remember the focused view to restore after relayout if the // data hasn't changed, or if the focused position is a header or footer. if (!dataChanged) { focusLayoutRestoreDirectChild = focusedChild; // Remember the specific view that had focus focusLayoutRestoreView = findFocus(); if (focusLayoutRestoreView != null) { // Tell it we are going to mess with it focusLayoutRestoreView.onStartTemporaryDetach(); } } requestFocus(); } // FIXME: We need a way to save current accessibility focus here // so that it can be restored after we re-attach the children on each // layout round. detachAllViewsFromParent(); switch (mLayoutMode) { case LAYOUT_SET_SELECTION: if (newSelected != null) { final int newSelectedStart = (mIsVertical ? newSelected.getTop() : newSelected.getLeft()); selected = fillFromSelection(newSelectedStart, start, end); } else { selected = fillFromMiddle(start, end); } break; case LAYOUT_SYNC: selected = fillSpecific(mSyncPosition, mSpecificStart); break; case LAYOUT_FORCE_BOTTOM: selected = fillBefore(mItemCount - 1, end); adjustViewsStartOrEnd(); break; case LAYOUT_FORCE_TOP: mFirstPosition = 0; selected = fillFromOffset(start); adjustViewsStartOrEnd(); break; case LAYOUT_SPECIFIC: selected = fillSpecific(reconcileSelectedPosition(), mSpecificStart); break; case LAYOUT_MOVE_SELECTION: selected = moveSelection(oldSelected, newSelected, delta, start, end); break; default: if (childCount == 0) { final int position = lookForSelectablePosition(0); setSelectedPositionInt(position); selected = fillFromOffset(start); } else { if (mSelectedPosition >= 0 && mSelectedPosition < mItemCount) { int offset = start; if (oldSelected != null) { offset = (mIsVertical ? oldSelected.getTop() : oldSelected.getLeft()); } selected = fillSpecific(mSelectedPosition, offset); } else if (mFirstPosition < mItemCount) { int offset = start; if (oldFirstChild != null) { offset = (mIsVertical ? oldFirstChild.getTop() : oldFirstChild.getLeft()); } selected = fillSpecific(mFirstPosition, offset); } else { selected = fillSpecific(0, start); } } break; } recycleBin.scrapActiveViews(); if (selected != null) { if (mItemsCanFocus && hasFocus() && !selected.hasFocus()) { final boolean focusWasTaken = (selected == focusLayoutRestoreDirectChild && focusLayoutRestoreView != null && focusLayoutRestoreView.requestFocus()) || selected.requestFocus(); if (!focusWasTaken) { // Selected item didn't take focus, fine, but still want // to make sure something else outside of the selected view // has focus final View focused = getFocusedChild(); if (focused != null) { focused.clearFocus(); } positionSelector(INVALID_POSITION, selected); } else { selected.setSelected(false); mSelectorRect.setEmpty(); } } else { positionSelector(INVALID_POSITION, selected); } mSelectedStart = (mIsVertical ? selected.getTop() : selected.getLeft()); } else { if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_DRAGGING) { View child = getChildAt(mMotionPosition - mFirstPosition); if (child != null) { positionSelector(mMotionPosition, child); } } else { mSelectedStart = 0; mSelectorRect.setEmpty(); } // Even if there is not selected position, we may need to restore // focus (i.e. something focusable in touch mode) if (hasFocus() && focusLayoutRestoreView != null) { focusLayoutRestoreView.requestFocus(); } } // Tell focus view we are done mucking with it, if it is still in // our view hierarchy. if (focusLayoutRestoreView != null && focusLayoutRestoreView.getWindowToken() != null) { focusLayoutRestoreView.onFinishTemporaryDetach(); } mLayoutMode = LAYOUT_NORMAL; mDataChanged = false; mNeedSync = false; setNextSelectedPositionInt(mSelectedPosition); if (mItemCount > 0) { checkSelectionChanged(); } invokeOnItemScrollListener(); } finally { if (!blockLayoutRequests) { mBlockLayoutRequests = false; mDataChanged = false; } } }
From source file:com.ferdi2005.secondgram.support.widget.RecyclerView.java
private void recoverFocusFromState() { if (!mPreserveFocusAfterLayout || mAdapter == null || !hasFocus() || getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS || (getDescendantFocusability() == FOCUS_BEFORE_DESCENDANTS && isFocused())) { // No-op if either of these cases happens: // 1. RV has no focus, or 2. RV blocks focus to its children, or 3. RV takes focus // before its children and is focused (i.e. it already stole the focus away from its // descendants). return;//from ww w . j av a 2s . co m } // only recover focus if RV itself has the focus or the focused view is hidden if (!isFocused()) { final View focusedChild = getFocusedChild(); if (IGNORE_DETACHED_FOCUSED_CHILD && (focusedChild.getParent() == null || !focusedChild.hasFocus())) { // Special handling of API 15-. A focused child can be invalid because mFocus is not // cleared when the child is detached (mParent = null), // This happens because clearFocus on API 15- does not invalidate mFocus of its // parent when this child is detached. // For API 16+, this is not an issue because requestFocus takes care of clearing the // prior detached focused child. For API 15- the problem happens in 2 cases because // clearChild does not call clearChildFocus on RV: 1. setFocusable(false) is called // for the current focused item which calls clearChild or 2. when the prior focused // child is removed, removeDetachedView called in layout step 3 which calls // clearChild. We should ignore this invalid focused child in all our calculations // for the next view to receive focus, and apply the focus recovery logic instead. if (mChildHelper.getChildCount() == 0) { // No children left. Request focus on the RV itself since one of its children // was holding focus previously. requestFocus(); return; } } else if (!mChildHelper.isHidden(focusedChild)) { // If the currently focused child is hidden, apply the focus recovery logic. // Otherwise return, i.e. the currently (unhidden) focused child is good enough :/. return; } } ViewHolder focusTarget = null; // RV first attempts to locate the previously focused item to request focus on using // mFocusedItemId. If such an item no longer exists, it then makes a best-effort attempt to // find the next best candidate to request focus on based on mFocusedItemPosition. if (mState.mFocusedItemId != NO_ID && mAdapter.hasStableIds()) { focusTarget = findViewHolderForItemId(mState.mFocusedItemId); } View viewToFocus = null; if (focusTarget == null || mChildHelper.isHidden(focusTarget.itemView) || !focusTarget.itemView.hasFocusable()) { if (mChildHelper.getChildCount() > 0) { // At this point, RV has focus and either of these conditions are true: // 1. There's no previously focused item either because RV received focused before // layout, or the previously focused item was removed, or RV doesn't have stable IDs // 2. Previous focus child is hidden, or 3. Previous focused child is no longer // focusable. In either of these cases, we make sure that RV still passes down the // focus to one of its focusable children using a best-effort algorithm. viewToFocus = findNextViewToFocus(); } } else { // looks like the focused item has been replaced with another view that represents the // same item in the adapter. Request focus on that. viewToFocus = focusTarget.itemView; } if (viewToFocus != null) { if (mState.mFocusedSubChildId != NO_ID) { View child = viewToFocus.findViewById(mState.mFocusedSubChildId); if (child != null && child.isFocusable()) { viewToFocus = child; } } viewToFocus.requestFocus(); } }
From source file:com.artifex.mupdf.view.ThumbnailViews.java
private void layoutChildren() { if (getWidth() == 0 || getHeight() == 0) { return;/*from w w w . ja v a 2 s.c o m*/ } final boolean blockLayoutRequests = mBlockLayoutRequests; if (!blockLayoutRequests) { mBlockLayoutRequests = true; } else { return; } try { invalidate(); if (mAdapter == null) { resetState(); return; } final int start = (mIsVertical ? getPaddingTop() : getPaddingLeft()); final int end = (mIsVertical ? getHeight() - getPaddingBottom() : getWidth() - getPaddingRight()); int childCount = getChildCount(); int index = 0; int delta = 0; View focusLayoutRestoreView = null; View selected = null; View oldSelected = null; View newSelected = null; View oldFirstChild = null; switch (mLayoutMode) { case LAYOUT_SET_SELECTION: index = mNextSelectedPosition - mFirstPosition; if (index >= 0 && index < childCount) { newSelected = getChildAt(index); } break; case LAYOUT_FORCE_TOP: case LAYOUT_FORCE_BOTTOM: case LAYOUT_SPECIFIC: case LAYOUT_SYNC: break; case LAYOUT_MOVE_SELECTION: default: // Remember the previously selected view index = mSelectedPosition - mFirstPosition; if (index >= 0 && index < childCount) { oldSelected = getChildAt(index); } // Remember the previous first child oldFirstChild = getChildAt(0); if (mNextSelectedPosition >= 0) { delta = mNextSelectedPosition - mSelectedPosition; } // Caution: newSelected might be null newSelected = getChildAt(index + delta); } final boolean dataChanged = mDataChanged; if (dataChanged) { handleDataChanged(); } // Handle the empty set by removing all views that are visible // and calling it a day if (mItemCount == 0) { resetState(); return; } else if (mItemCount != mAdapter.getCount()) { throw new IllegalStateException("The content of the adapter has changed but " + "TwoWayView did not receive a notification. Make sure the content of " + "your adapter is not modified from a background thread, but only " + "from the UI thread. [in TwoWayView(" + getId() + ", " + getClass() + ") with Adapter(" + mAdapter.getClass() + ")]"); } setSelectedPositionInt(mNextSelectedPosition); // Reset the focus restoration View focusLayoutRestoreDirectChild = null; // Pull all children into the RecycleBin. // These views will be reused if possible final int firstPosition = mFirstPosition; final RecycleBin recycleBin = mRecycler; if (dataChanged) { for (int i = 0; i < childCount; i++) { recycleBin.addScrapView(getChildAt(i), firstPosition + i); } } else { recycleBin.fillActiveViews(childCount, firstPosition); } // Take focus back to us temporarily to avoid the eventual // call to clear focus when removing the focused child below // from messing things up when ViewAncestor assigns focus back // to someone else. final View focusedChild = getFocusedChild(); if (focusedChild != null) { // We can remember the focused view to restore after relayout if // the // data hasn't changed, or if the focused position is a header // or footer. if (!dataChanged) { focusLayoutRestoreDirectChild = focusedChild; // Remember the specific view that had focus focusLayoutRestoreView = findFocus(); if (focusLayoutRestoreView != null) { // Tell it we are going to mess with it focusLayoutRestoreView.onStartTemporaryDetach(); } } requestFocus(); } // FIXME: We need a way to save current accessibility focus here // so that it can be restored after we re-attach the children on // each // layout round. detachAllViewsFromParent(); switch (mLayoutMode) { case LAYOUT_SET_SELECTION: if (newSelected != null) { final int newSelectedStart = (mIsVertical ? newSelected.getTop() : newSelected.getLeft()); selected = fillFromSelection(newSelectedStart, start, end); } else { selected = fillFromMiddle(start, end); } break; case LAYOUT_SYNC: selected = fillSpecific(mSyncPosition, mSpecificStart); break; case LAYOUT_FORCE_BOTTOM: selected = fillBefore(mItemCount - 1, end); adjustViewsStartOrEnd(); break; case LAYOUT_FORCE_TOP: mFirstPosition = 0; selected = fillFromOffset(start); adjustViewsStartOrEnd(); break; case LAYOUT_SPECIFIC: selected = fillSpecific(reconcileSelectedPosition(), mSpecificStart); break; case LAYOUT_MOVE_SELECTION: selected = moveSelection(oldSelected, newSelected, delta, start, end); break; default: if (childCount == 0) { final int position = lookForSelectablePosition(0); setSelectedPositionInt(position); selected = fillFromOffset(start); } else { if (mSelectedPosition >= 0 && mSelectedPosition < mItemCount) { int offset = start; if (oldSelected != null) { offset = (mIsVertical ? oldSelected.getTop() : oldSelected.getLeft()); } selected = fillSpecific(mSelectedPosition, offset); } else if (mFirstPosition < mItemCount) { int offset = start; if (oldFirstChild != null) { offset = (mIsVertical ? oldFirstChild.getTop() : oldFirstChild.getLeft()); } selected = fillSpecific(mFirstPosition, offset); } else { selected = fillSpecific(0, start); } } break; } recycleBin.scrapActiveViews(); if (selected != null) { if (mItemsCanFocus && hasFocus() && !selected.hasFocus()) { final boolean focusWasTaken = (selected == focusLayoutRestoreDirectChild && focusLayoutRestoreView != null && focusLayoutRestoreView.requestFocus()) || selected.requestFocus(); if (!focusWasTaken) { // Selected item didn't take focus, fine, but still want // to make sure something else outside of the selected // view // has focus final View focused = getFocusedChild(); if (focused != null) { focused.clearFocus(); } positionSelector(INVALID_POSITION, selected); } else { selected.setSelected(false); mSelectorRect.setEmpty(); } } else { positionSelector(INVALID_POSITION, selected); } mSelectedStart = (mIsVertical ? selected.getTop() : selected.getLeft()); } else { if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_DRAGGING) { View child = getChildAt(mMotionPosition - mFirstPosition); if (child != null) { positionSelector(mMotionPosition, child); } } else { mSelectedStart = 0; mSelectorRect.setEmpty(); } // Even if there is not selected position, we may need to // restore // focus (i.e. something focusable in touch mode) if (hasFocus() && focusLayoutRestoreView != null) { focusLayoutRestoreView.requestFocus(); } } // Tell focus view we are done mucking with it, if it is still in // our view hierarchy. if (focusLayoutRestoreView != null && focusLayoutRestoreView.getWindowToken() != null) { focusLayoutRestoreView.onFinishTemporaryDetach(); } mLayoutMode = LAYOUT_NORMAL; mDataChanged = false; mNeedSync = false; setNextSelectedPositionInt(mSelectedPosition); if (mItemCount > 0) { checkSelectionChanged(); } invokeOnItemScrollListener(); } finally { if (!blockLayoutRequests) { mBlockLayoutRequests = false; mDataChanged = false; } } }
From source file:com.artifex.mupdflib.TwoWayView.java
private void layoutChildren() { if (getWidth() == 0 || getHeight() == 0) { return;/* w w w .j av a2 s . c o m*/ } final boolean blockLayoutRequests = mBlockLayoutRequests; if (!blockLayoutRequests) { mBlockLayoutRequests = true; } else { return; } try { invalidate(); if (mAdapter == null) { resetState(); return; } final int start = getStartEdge(); final int end = getEndEdge(); int childCount = getChildCount(); int index = 0; int delta = 0; View focusLayoutRestoreView = null; View selected = null; View oldSelected = null; View newSelected = null; View oldFirstChild = null; switch (mLayoutMode) { case LAYOUT_SET_SELECTION: index = mNextSelectedPosition - mFirstPosition; if (index >= 0 && index < childCount) { newSelected = getChildAt(index); } break; case LAYOUT_FORCE_TOP: case LAYOUT_FORCE_BOTTOM: case LAYOUT_SPECIFIC: case LAYOUT_SYNC: break; case LAYOUT_MOVE_SELECTION: default: // Remember the previously selected view index = mSelectedPosition - mFirstPosition; if (index >= 0 && index < childCount) { oldSelected = getChildAt(index); } // Remember the previous first child oldFirstChild = getChildAt(0); if (mNextSelectedPosition >= 0) { delta = mNextSelectedPosition - mSelectedPosition; } // Caution: newSelected might be null newSelected = getChildAt(index + delta); } final boolean dataChanged = mDataChanged; if (dataChanged) { handleDataChanged(); } // Handle the empty set by removing all views that are visible // and calling it a day if (mItemCount == 0) { resetState(); return; } else if (mItemCount != mAdapter.getCount()) { throw new IllegalStateException("The content of the adapter has changed but " + "TwoWayView did not receive a notification. Make sure the content of " + "your adapter is not modified from a background thread, but only " + "from the UI thread. [in TwoWayView(" + getId() + ", " + getClass() + ") with Adapter(" + mAdapter.getClass() + ")]"); } setSelectedPositionInt(mNextSelectedPosition); // Reset the focus restoration View focusLayoutRestoreDirectChild = null; // Pull all children into the RecycleBin. // These views will be reused if possible final int firstPosition = mFirstPosition; final RecycleBin recycleBin = mRecycler; if (dataChanged) { for (int i = 0; i < childCount; i++) { recycleBin.addScrapView(getChildAt(i), firstPosition + i); } } else { recycleBin.fillActiveViews(childCount, firstPosition); } // Take focus back to us temporarily to avoid the eventual // call to clear focus when removing the focused child below // from messing things up when ViewAncestor assigns focus back // to someone else. final View focusedChild = getFocusedChild(); if (focusedChild != null) { // We can remember the focused view to restore after relayout if the // data hasn't changed, or if the focused position is a header or footer. if (!dataChanged) { focusLayoutRestoreDirectChild = focusedChild; // Remember the specific view that had focus focusLayoutRestoreView = findFocus(); if (focusLayoutRestoreView != null) { // Tell it we are going to mess with it focusLayoutRestoreView.onStartTemporaryDetach(); } } requestFocus(); } // FIXME: We need a way to save current accessibility focus here // so that it can be restored after we re-attach the children on each // layout round. detachAllViewsFromParent(); switch (mLayoutMode) { case LAYOUT_SET_SELECTION: if (newSelected != null) { final int newSelectedStart = getChildStartEdge(newSelected); selected = fillFromSelection(newSelectedStart, start, end); } else { selected = fillFromMiddle(start, end); } break; case LAYOUT_SYNC: selected = fillSpecific(mSyncPosition, mSpecificStart); break; case LAYOUT_FORCE_BOTTOM: selected = fillBefore(mItemCount - 1, end); adjustViewsStartOrEnd(); break; case LAYOUT_FORCE_TOP: mFirstPosition = 0; selected = fillFromOffset(start); adjustViewsStartOrEnd(); break; case LAYOUT_SPECIFIC: selected = fillSpecific(reconcileSelectedPosition(), mSpecificStart); break; case LAYOUT_MOVE_SELECTION: selected = moveSelection(oldSelected, newSelected, delta, start, end); break; default: if (childCount == 0) { final int position = lookForSelectablePosition(0); setSelectedPositionInt(position); selected = fillFromOffset(start); } else { if (mSelectedPosition >= 0 && mSelectedPosition < mItemCount) { int offset = start; if (oldSelected != null) { offset = getChildStartEdge(oldSelected); } selected = fillSpecific(mSelectedPosition, offset); } else if (mFirstPosition < mItemCount) { int offset = start; if (oldFirstChild != null) { offset = getChildStartEdge(oldFirstChild); } selected = fillSpecific(mFirstPosition, offset); } else { selected = fillSpecific(0, start); } } break; } recycleBin.scrapActiveViews(); if (selected != null) { if (mItemsCanFocus && hasFocus() && !selected.hasFocus()) { final boolean focusWasTaken = (selected == focusLayoutRestoreDirectChild && focusLayoutRestoreView != null && focusLayoutRestoreView.requestFocus()) || selected.requestFocus(); if (!focusWasTaken) { // Selected item didn't take focus, fine, but still want // to make sure something else outside of the selected view // has focus final View focused = getFocusedChild(); if (focused != null) { focused.clearFocus(); } positionSelector(INVALID_POSITION, selected); } else { selected.setSelected(false); mSelectorRect.setEmpty(); } } else { positionSelector(INVALID_POSITION, selected); } mSelectedStart = getChildStartEdge(selected); } else { if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_DRAGGING) { View child = getChildAt(mMotionPosition - mFirstPosition); if (child != null) { positionSelector(mMotionPosition, child); } } else { mSelectedStart = 0; mSelectorRect.setEmpty(); } // Even if there is not selected position, we may need to restore // focus (i.e. something focusable in touch mode) if (hasFocus() && focusLayoutRestoreView != null) { focusLayoutRestoreView.requestFocus(); } } // Tell focus view we are done mucking with it, if it is still in // our view hierarchy. if (focusLayoutRestoreView != null && focusLayoutRestoreView.getWindowToken() != null) { focusLayoutRestoreView.onFinishTemporaryDetach(); } mLayoutMode = LAYOUT_NORMAL; mDataChanged = false; mNeedSync = false; setNextSelectedPositionInt(mSelectedPosition); if (mItemCount > 0) { checkSelectionChanged(); } invokeOnItemScrollListener(); } finally { if (!blockLayoutRequests) { mBlockLayoutRequests = false; mDataChanged = false; } } }