List of usage examples for android.view View isFocusable
@ViewDebug.ExportedProperty(category = "focus") public final boolean isFocusable()
From source file:com.kozhevin.example.carousel.CarouselLayoutManager.java
/** * The magic functions :). Fills the given layout, defined by the renderState. This is fairly * independent from the rest of the {@link android.support.v7.widget.LinearLayoutManager} and with little change, can be made publicly available * as a helper class./*from w ww .jav a 2 s .c o m*/ * * @param recycler * Current recycler that is attached to RecyclerView * @param renderState * Configuration on how we should fill out the available space. * @param state * Context passed by the RecyclerView to control scroll steps. * @param stopOnFocusable * If true, filling stops in the first focusable new child * @return Number of pixels that it added. Useful for scoll functions. */ private int fill(RecyclerView.Recycler recycler, RenderState renderState, RecyclerView.State state, boolean stopOnFocusable) { // max offset we should set is mFastScroll + available final int start = renderState.mAvailable; if (renderState.mScrollingOffset != RenderState.SCOLLING_OFFSET_NaN) { // TODO ugly bug fix. should not happen if (renderState.mAvailable < 0) { renderState.mScrollingOffset += renderState.mAvailable; } recycleByRenderState(recycler, renderState); } int remainingSpace = renderState.mAvailable + renderState.mExtra; while (remainingSpace > 0 && renderState.hasMore(state)) { View view = renderState.next(recycler); if (view == null) { if (IS_DEBUG && renderState.mScrapList == null) { throw new RuntimeException("received null view when unexpected"); } // if we are laying out views in scrap, this may return null which means there is // no more items to layout. break; } RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams(); if (!params.isItemRemoved() && mRenderState.mScrapList == null) { if (mShouldReverseLayout == (renderState.mLayoutDirection == RenderState.LAYOUT_START)) { addView(view); } else { addView(view, 0); } } measureChildWithMargins(view, 0, 0); int consumed = 0; //mOrientationHelper.getDecoratedMeasurement(view); if (mOrientation == VERTICAL) { consumed = (int) ((getWidth() - getPaddingLeft() - getPaddingRight()) * DEFAULT_WIDTH_VIEW_RATIO); } else { consumed = (int) ((getWidth() - getPaddingTop() - getPaddingBottom()) * DEFAULT_WIDTH_VIEW_RATIO); } int left, top, right, bottom; if (mOrientation == VERTICAL) { if (isLayoutRTL()) { right = getWidth() - getPaddingRight(); left = right - mOrientationHelper.getDecoratedMeasurementInOther(view); } else { left = getPaddingLeft(); right = left + mOrientationHelper.getDecoratedMeasurementInOther(view); } if (renderState.mLayoutDirection == RenderState.LAYOUT_START) { bottom = renderState.mOffset; top = renderState.mOffset - consumed; } else { top = renderState.mOffset; bottom = renderState.mOffset + consumed; } } else { top = getPaddingTop(); bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view); if (renderState.mLayoutDirection == RenderState.LAYOUT_START) { right = renderState.mOffset; left = renderState.mOffset - consumed; } else { left = renderState.mOffset; right = renderState.mOffset + consumed; } } // We calculate everything with View's bounding box (which includes decor and margins) // To calculate correct layout position, we subtract margins. layoutDecorated(view, left + params.leftMargin, top + params.topMargin, right - params.rightMargin, bottom - params.bottomMargin); if (IS_DEBUG) { Log.d(TAG, "laid out child at position " + getPosition(view) + ", with l:" + (left + params.leftMargin) + ", t:" + (top + params.topMargin) + ", r:" + (right - params.rightMargin) + ", b:" + (bottom - params.bottomMargin)); } renderState.mOffset += consumed * renderState.mLayoutDirection; if (!params.isItemRemoved()) { renderState.mAvailable -= consumed; // we keep a separate remaining space because mAvailable is important for recycling remainingSpace -= consumed; } if (renderState.mScrollingOffset != RenderState.SCOLLING_OFFSET_NaN) { renderState.mScrollingOffset += consumed; if (renderState.mAvailable < 0) { renderState.mScrollingOffset += renderState.mAvailable; } recycleByRenderState(recycler, renderState); } if (stopOnFocusable && view.isFocusable()) { break; } if (state != null && state.getTargetScrollPosition() == getPosition(view)) { break; } } makeScaleView(renderState); updatePositionForInsert(); if (IS_DEBUG) { validateChildOrder(); } return start - renderState.mAvailable; }
From source file:cn.ismartv.tvrecyclerview.widget.GridLayoutManager.java
@Override void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state, LayoutState layoutState, LayoutChunkResult result) {/*w w w .j a v a 2 s. com*/ final int otherDirSpecMode = mOrientationHelper.getModeInOther(); final boolean flexibleInOtherDir = otherDirSpecMode != View.MeasureSpec.EXACTLY; final int currentOtherDirSize = getChildCount() > 0 ? mCachedBorders[mSpanCount] : 0; // if grid layout's dimensions are not specified, let the new row change the measurements // This is not perfect since we not covering all rows but still solves an important case // where they may have a header row which should be laid out according to children. if (flexibleInOtherDir) { updateMeasurements(); // reset measurements } final boolean layingOutInPrimaryDirection = layoutState.mItemDirection == LayoutState.ITEM_DIRECTION_TAIL; int count = 0; int consumedSpanCount = 0; int remainingSpan = mSpanCount; if (!layingOutInPrimaryDirection) { int itemSpanIndex = getSpanIndex(recycler, state, layoutState.mCurrentPosition); int itemSpanSize = getSpanSize(recycler, state, layoutState.mCurrentPosition); remainingSpan = itemSpanIndex + itemSpanSize; } while (count < mSpanCount && layoutState.hasMore(state) && remainingSpan > 0) { int pos = layoutState.mCurrentPosition; final int spanSize = getSpanSize(recycler, state, pos); if (spanSize > mSpanCount) { throw new IllegalArgumentException("Item at position " + pos + " requires " + spanSize + " spans but GridLayoutManager has only " + mSpanCount + " spans."); } remainingSpan -= spanSize; if (remainingSpan < 0) { break; // item did not fit into this row or column } View view = layoutState.next(recycler); if (view == null) { break; } consumedSpanCount += spanSize; mSet[count] = view; count++; } if (count == 0) { result.mFinished = true; return; } int maxSize = 0; float maxSizeInOther = 0; // use a float to get size per span // we should assign spans before item decor offsets are calculated assignSpans(recycler, state, count, consumedSpanCount, layingOutInPrimaryDirection); for (int i = 0; i < count; i++) { View view = mSet[i]; if (layoutState.mScrapList == null) { if (layingOutInPrimaryDirection) { addView(view); } else { addView(view, 0); } } else { if (layingOutInPrimaryDirection) { addDisappearingView(view); } else { addDisappearingView(view, 0); } } calculateItemDecorationsForChild(view, mDecorInsets); measureChild(view, otherDirSpecMode, false); final int size = mOrientationHelper.getDecoratedMeasurement(view); if (size > maxSize) { maxSize = size; } final LayoutParams lp = (LayoutParams) view.getLayoutParams(); final float otherSize = 1f * mOrientationHelper.getDecoratedMeasurementInOther(view) / lp.mSpanSize; if (otherSize > maxSizeInOther) { maxSizeInOther = otherSize; } } if (flexibleInOtherDir) { // re-distribute columns guessMeasurement(maxSizeInOther, currentOtherDirSize); // now we should re-measure any item that was match parent. maxSize = 0; for (int i = 0; i < count; i++) { View view = mSet[i]; measureChild(view, View.MeasureSpec.EXACTLY, true); final int size = mOrientationHelper.getDecoratedMeasurement(view); if (size > maxSize) { maxSize = size; } } } // Views that did not measure the maxSize has to be re-measured // We will stop doing this once we introduce Gravity in the GLM layout params for (int i = 0; i < count; i++) { final View view = mSet[i]; if (mOrientationHelper.getDecoratedMeasurement(view) != maxSize) { final LayoutParams lp = (LayoutParams) view.getLayoutParams(); final Rect decorInsets = lp.mDecorInsets; final int verticalInsets = decorInsets.top + decorInsets.bottom + lp.topMargin + lp.bottomMargin; final int horizontalInsets = decorInsets.left + decorInsets.right + lp.leftMargin + lp.rightMargin; final int totalSpaceInOther = getSpaceForSpanRange(lp.mSpanIndex, lp.mSpanSize); final int wSpec; final int hSpec; if (mOrientation == VERTICAL) { wSpec = getChildMeasureSpec(totalSpaceInOther, View.MeasureSpec.EXACTLY, horizontalInsets, lp.width, false); hSpec = View.MeasureSpec.makeMeasureSpec(maxSize - verticalInsets, View.MeasureSpec.EXACTLY); } else { wSpec = View.MeasureSpec.makeMeasureSpec(maxSize - horizontalInsets, View.MeasureSpec.EXACTLY); hSpec = getChildMeasureSpec(totalSpaceInOther, View.MeasureSpec.EXACTLY, verticalInsets, lp.height, false); } measureChildWithDecorationsAndMargin(view, wSpec, hSpec, true); } } result.mConsumed = maxSize; int left = 0, right = 0, top = 0, bottom = 0; if (mOrientation == VERTICAL) { if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) { bottom = layoutState.mOffset; top = bottom - maxSize; } else { top = layoutState.mOffset; bottom = top + maxSize; } } else { if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) { right = layoutState.mOffset; left = right - maxSize; } else { left = layoutState.mOffset; right = left + maxSize; } } for (int i = 0; i < count; i++) { View view = mSet[i]; LayoutParams params = (LayoutParams) view.getLayoutParams(); if (mOrientation == VERTICAL) { if (isLayoutRTL()) { right = getPaddingLeft() + mCachedBorders[mSpanCount - params.mSpanIndex]; left = right - mOrientationHelper.getDecoratedMeasurementInOther(view); } else { left = getPaddingLeft() + mCachedBorders[params.mSpanIndex]; right = left + mOrientationHelper.getDecoratedMeasurementInOther(view); } } else { top = getPaddingTop() + mCachedBorders[params.mSpanIndex]; bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view); } // We calculate everything with View's bounding box (which includes decor and margins) // To calculate correct layout position, we subtract margins. layoutDecoratedWithMargins(view, left, top, right, bottom); if (DEBUG) { Log.d(TAG, "laid out child at position " + getPosition(view) + ", with l:" + (left + params.leftMargin) + ", t:" + (top + params.topMargin) + ", r:" + (right - params.rightMargin) + ", b:" + (bottom - params.bottomMargin) + ", span:" + params.mSpanIndex + ", spanSize:" + params.mSpanSize); } // Consume the available space if the view is not removed OR changed if (params.isItemRemoved() || params.isItemChanged()) { result.mIgnoreConsumed = true; } result.mFocusable |= view.isFocusable(); } Arrays.fill(mSet, null); }
From source file:cn.ismartv.tvrecyclerview.widget.StaggeredGridLayoutManager.java
private int fill(RecyclerView.Recycler recycler, LayoutState layoutState, RecyclerView.State state) { mRemainingSpans.set(0, mSpanCount, true); // The target position we are trying to reach. final int targetLine; // Line of the furthest row. if (mLayoutState.mInfinite) { if (layoutState.mLayoutDirection == LAYOUT_END) { targetLine = Integer.MAX_VALUE; } else { // LAYOUT_START targetLine = Integer.MIN_VALUE; }// w w w . j a va 2s . c o m } else { if (layoutState.mLayoutDirection == LAYOUT_END) { targetLine = layoutState.mEndLine + layoutState.mAvailable; } else { // LAYOUT_START targetLine = layoutState.mStartLine - layoutState.mAvailable; } } updateAllRemainingSpans(layoutState.mLayoutDirection, targetLine); if (DEBUG) { Log.d(TAG, "FILLING targetLine: " + targetLine + "," + "remaining spans:" + mRemainingSpans + ", state: " + layoutState); } // the default coordinate to add new view. final int defaultNewViewLine = mShouldReverseLayout ? mPrimaryOrientation.getEndAfterPadding() : mPrimaryOrientation.getStartAfterPadding(); boolean added = false; while (layoutState.hasMore(state) && (mLayoutState.mInfinite || !mRemainingSpans.isEmpty())) { View view = layoutState.next(recycler); LayoutParams lp = ((LayoutParams) view.getLayoutParams()); final int position = lp.getViewLayoutPosition(); final int spanIndex = mLazySpanLookup.getSpan(position); Span currentSpan; final boolean assignSpan = spanIndex == LayoutParams.INVALID_SPAN_ID; if (assignSpan) { currentSpan = lp.mFullSpan ? mSpans[0] : getNextSpan(layoutState); mLazySpanLookup.setSpan(position, currentSpan); if (DEBUG) { Log.d(TAG, "assigned " + currentSpan.mIndex + " for " + position); } } else { if (DEBUG) { Log.d(TAG, "using " + spanIndex + " for pos " + position); } currentSpan = mSpans[spanIndex]; } // assign span before measuring so that item decorators can get updated span index lp.mSpan = currentSpan; if (layoutState.mLayoutDirection == LAYOUT_END) { addView(view); } else { addView(view, 0); } measureChildWithDecorationsAndMargin(view, lp, false); final int start; final int end; if (layoutState.mLayoutDirection == LAYOUT_END) { start = lp.mFullSpan ? getMaxEnd(defaultNewViewLine) : currentSpan.getEndLine(defaultNewViewLine); end = start + mPrimaryOrientation.getDecoratedMeasurement(view); if (assignSpan && lp.mFullSpan) { LazySpanLookup.FullSpanItem fullSpanItem; fullSpanItem = createFullSpanItemFromEnd(start); fullSpanItem.mGapDir = LAYOUT_START; fullSpanItem.mPosition = position; mLazySpanLookup.addFullSpanItem(fullSpanItem); } } else { end = lp.mFullSpan ? getMinStart(defaultNewViewLine) : currentSpan.getStartLine(defaultNewViewLine); start = end - mPrimaryOrientation.getDecoratedMeasurement(view); if (assignSpan && lp.mFullSpan) { LazySpanLookup.FullSpanItem fullSpanItem; fullSpanItem = createFullSpanItemFromStart(end); fullSpanItem.mGapDir = LAYOUT_END; fullSpanItem.mPosition = position; mLazySpanLookup.addFullSpanItem(fullSpanItem); } } // check if this item may create gaps in the future if (lp.mFullSpan && layoutState.mItemDirection == ITEM_DIRECTION_HEAD) { if (assignSpan) { mLaidOutInvalidFullSpan = true; } else { final boolean hasInvalidGap; if (layoutState.mLayoutDirection == LAYOUT_END) { hasInvalidGap = !areAllEndsEqual(); } else { // layoutState.mLayoutDirection == LAYOUT_START hasInvalidGap = !areAllStartsEqual(); } if (hasInvalidGap) { final LazySpanLookup.FullSpanItem fullSpanItem = mLazySpanLookup.getFullSpanItem(position); if (fullSpanItem != null) { fullSpanItem.mHasUnwantedGapAfter = true; } mLaidOutInvalidFullSpan = true; } } } attachViewToSpans(view, lp, layoutState); final int otherStart; final int otherEnd; if (isLayoutRTL() && mOrientation == VERTICAL) { otherEnd = lp.mFullSpan ? mSecondaryOrientation.getEndAfterPadding() : mSecondaryOrientation.getEndAfterPadding() - (mSpanCount - 1 - currentSpan.mIndex) * mSizePerSpan; otherStart = otherEnd - mSecondaryOrientation.getDecoratedMeasurement(view); } else { otherStart = lp.mFullSpan ? mSecondaryOrientation.getStartAfterPadding() : currentSpan.mIndex * mSizePerSpan + mSecondaryOrientation.getStartAfterPadding(); otherEnd = otherStart + mSecondaryOrientation.getDecoratedMeasurement(view); } if (mOrientation == VERTICAL) { layoutDecoratedWithMargins(view, otherStart, start, otherEnd, end); } else { layoutDecoratedWithMargins(view, start, otherStart, end, otherEnd); } if (lp.mFullSpan) { updateAllRemainingSpans(mLayoutState.mLayoutDirection, targetLine); } else { updateRemainingSpans(currentSpan, mLayoutState.mLayoutDirection, targetLine); } recycle(recycler, mLayoutState); if (mLayoutState.mStopInFocusable && view.isFocusable()) { if (lp.mFullSpan) { mRemainingSpans.clear(); } else { mRemainingSpans.set(currentSpan.mIndex, false); } } added = true; } if (!added) { recycle(recycler, mLayoutState); } final int diff; if (mLayoutState.mLayoutDirection == LAYOUT_START) { final int minStart = getMinStart(mPrimaryOrientation.getStartAfterPadding()); diff = mPrimaryOrientation.getStartAfterPadding() - minStart; } else { final int maxEnd = getMaxEnd(mPrimaryOrientation.getEndAfterPadding()); diff = maxEnd - mPrimaryOrientation.getEndAfterPadding(); } return diff > 0 ? Math.min(layoutState.mAvailable, diff) : 0; }
From source file:ir.besteveryeverapp.telegram.support.widget.StaggeredGridLayoutManager.java
private int fill(RecyclerView.Recycler recycler, LayoutState layoutState, RecyclerView.State state) { mRemainingSpans.set(0, mSpanCount, true); // The target position we are trying to reach. final int targetLine; // Line of the furthest row. if (mLayoutState.mInfinite) { if (layoutState.mLayoutDirection == LayoutState.LAYOUT_END) { targetLine = Integer.MAX_VALUE; } else { // LAYOUT_START targetLine = Integer.MIN_VALUE; }//from w w w . j ava 2 s.com } else { if (layoutState.mLayoutDirection == LayoutState.LAYOUT_END) { targetLine = layoutState.mEndLine + layoutState.mAvailable; } else { // LAYOUT_START targetLine = layoutState.mStartLine - layoutState.mAvailable; } } updateAllRemainingSpans(layoutState.mLayoutDirection, targetLine); if (DEBUG) { Log.d(TAG, "FILLING targetLine: " + targetLine + "," + "remaining spans:" + mRemainingSpans + ", state: " + layoutState); } // the default coordinate to add new view. final int defaultNewViewLine = mShouldReverseLayout ? mPrimaryOrientation.getEndAfterPadding() : mPrimaryOrientation.getStartAfterPadding(); boolean added = false; while (layoutState.hasMore(state) && (mLayoutState.mInfinite || !mRemainingSpans.isEmpty())) { View view = layoutState.next(recycler); LayoutParams lp = ((LayoutParams) view.getLayoutParams()); final int position = lp.getViewLayoutPosition(); final int spanIndex = mLazySpanLookup.getSpan(position); Span currentSpan; final boolean assignSpan = spanIndex == LayoutParams.INVALID_SPAN_ID; if (assignSpan) { currentSpan = lp.mFullSpan ? mSpans[0] : getNextSpan(layoutState); mLazySpanLookup.setSpan(position, currentSpan); if (DEBUG) { Log.d(TAG, "assigned " + currentSpan.mIndex + " for " + position); } } else { if (DEBUG) { Log.d(TAG, "using " + spanIndex + " for pos " + position); } currentSpan = mSpans[spanIndex]; } // assign span before measuring so that item decorators can get updated span index lp.mSpan = currentSpan; if (layoutState.mLayoutDirection == LayoutState.LAYOUT_END) { addView(view); } else { addView(view, 0); } measureChildWithDecorationsAndMargin(view, lp, false); final int start; final int end; if (layoutState.mLayoutDirection == LayoutState.LAYOUT_END) { start = lp.mFullSpan ? getMaxEnd(defaultNewViewLine) : currentSpan.getEndLine(defaultNewViewLine); end = start + mPrimaryOrientation.getDecoratedMeasurement(view); if (assignSpan && lp.mFullSpan) { LazySpanLookup.FullSpanItem fullSpanItem; fullSpanItem = createFullSpanItemFromEnd(start); fullSpanItem.mGapDir = LayoutState.LAYOUT_START; fullSpanItem.mPosition = position; mLazySpanLookup.addFullSpanItem(fullSpanItem); } } else { end = lp.mFullSpan ? getMinStart(defaultNewViewLine) : currentSpan.getStartLine(defaultNewViewLine); start = end - mPrimaryOrientation.getDecoratedMeasurement(view); if (assignSpan && lp.mFullSpan) { LazySpanLookup.FullSpanItem fullSpanItem; fullSpanItem = createFullSpanItemFromStart(end); fullSpanItem.mGapDir = LayoutState.LAYOUT_END; fullSpanItem.mPosition = position; mLazySpanLookup.addFullSpanItem(fullSpanItem); } } // check if this item may create gaps in the future if (lp.mFullSpan && layoutState.mItemDirection == LayoutState.ITEM_DIRECTION_HEAD) { if (assignSpan) { mLaidOutInvalidFullSpan = true; } else { final boolean hasInvalidGap; if (layoutState.mLayoutDirection == LayoutState.LAYOUT_END) { hasInvalidGap = !areAllEndsEqual(); } else { // layoutState.mLayoutDirection == LAYOUT_START hasInvalidGap = !areAllStartsEqual(); } if (hasInvalidGap) { final LazySpanLookup.FullSpanItem fullSpanItem = mLazySpanLookup.getFullSpanItem(position); if (fullSpanItem != null) { fullSpanItem.mHasUnwantedGapAfter = true; } mLaidOutInvalidFullSpan = true; } } } attachViewToSpans(view, lp, layoutState); final int otherStart; final int otherEnd; if (isLayoutRTL() && mOrientation == VERTICAL) { otherEnd = lp.mFullSpan ? mSecondaryOrientation.getEndAfterPadding() : mSecondaryOrientation.getEndAfterPadding() - (mSpanCount - 1 - currentSpan.mIndex) * mSizePerSpan; otherStart = otherEnd - mSecondaryOrientation.getDecoratedMeasurement(view); } else { otherStart = lp.mFullSpan ? mSecondaryOrientation.getStartAfterPadding() : currentSpan.mIndex * mSizePerSpan + mSecondaryOrientation.getStartAfterPadding(); otherEnd = otherStart + mSecondaryOrientation.getDecoratedMeasurement(view); } if (mOrientation == VERTICAL) { layoutDecoratedWithMargins(view, otherStart, start, otherEnd, end); } else { layoutDecoratedWithMargins(view, start, otherStart, end, otherEnd); } if (lp.mFullSpan) { updateAllRemainingSpans(mLayoutState.mLayoutDirection, targetLine); } else { updateRemainingSpans(currentSpan, mLayoutState.mLayoutDirection, targetLine); } recycle(recycler, mLayoutState); if (mLayoutState.mStopInFocusable && view.isFocusable()) { if (lp.mFullSpan) { mRemainingSpans.clear(); } else { mRemainingSpans.set(currentSpan.mIndex, false); } } added = true; } if (!added) { recycle(recycler, mLayoutState); } final int diff; if (mLayoutState.mLayoutDirection == LayoutState.LAYOUT_START) { final int minStart = getMinStart(mPrimaryOrientation.getStartAfterPadding()); diff = mPrimaryOrientation.getStartAfterPadding() - minStart; } else { final int maxEnd = getMaxEnd(mPrimaryOrientation.getEndAfterPadding()); diff = maxEnd - mPrimaryOrientation.getEndAfterPadding(); } return diff > 0 ? Math.min(layoutState.mAvailable, diff) : 0; }
From source file:com.b44t.messenger.support.widget.GridLayoutManager.java
@Override void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state, LayoutState layoutState, LayoutChunkResult result) {//www . j a v a 2 s.co m final int otherDirSpecMode = mOrientationHelper.getModeInOther(); final boolean flexibleInOtherDir = otherDirSpecMode != View.MeasureSpec.EXACTLY; final int currentOtherDirSize = getChildCount() > 0 ? mCachedBorders[mSpanCount] : 0; // if grid layout's dimensions are not specified, let the new row change the measurements // This is not perfect since we not covering all rows but still solves an important case // where they may have a header row which should be laid out according to children. if (flexibleInOtherDir) { updateMeasurements(); // reset measurements } final boolean layingOutInPrimaryDirection = layoutState.mItemDirection == LayoutState.ITEM_DIRECTION_TAIL; int count = 0; int consumedSpanCount = 0; int remainingSpan = mSpanCount; if (!layingOutInPrimaryDirection) { int itemSpanIndex = getSpanIndex(recycler, state, layoutState.mCurrentPosition); int itemSpanSize = getSpanSize(recycler, state, layoutState.mCurrentPosition); remainingSpan = itemSpanIndex + itemSpanSize; } while (count < mSpanCount && layoutState.hasMore(state) && remainingSpan > 0) { int pos = layoutState.mCurrentPosition; final int spanSize = getSpanSize(recycler, state, pos); if (spanSize > mSpanCount) { throw new IllegalArgumentException("Item at position " + pos + " requires " + spanSize + " spans but GridLayoutManager has only " + mSpanCount + " spans."); } remainingSpan -= spanSize; if (remainingSpan < 0) { break; // item did not fit into this row or column } View view = layoutState.next(recycler); if (view == null) { break; } consumedSpanCount += spanSize; mSet[count] = view; count++; } if (count == 0) { result.mFinished = true; return; } int maxSize = 0; float maxSizeInOther = 0; // use a float to get size per span // we should assign spans before item decor offsets are calculated assignSpans(recycler, state, count, consumedSpanCount, layingOutInPrimaryDirection); for (int i = 0; i < count; i++) { View view = mSet[i]; if (layoutState.mScrapList == null) { if (layingOutInPrimaryDirection) { addView(view); } else { addView(view, 0); } } else { if (layingOutInPrimaryDirection) { addDisappearingView(view); } else { addDisappearingView(view, 0); } } final LayoutParams lp = (LayoutParams) view.getLayoutParams(); final int spec = getChildMeasureSpec( mCachedBorders[lp.mSpanIndex + lp.mSpanSize] - mCachedBorders[lp.mSpanIndex], otherDirSpecMode, 0, mOrientation == HORIZONTAL ? lp.height : lp.width, false); final int mainSpec = getChildMeasureSpec(mOrientationHelper.getTotalSpace(), mOrientationHelper.getMode(), 0, mOrientation == VERTICAL ? lp.height : lp.width, true); // Unless the child has MATCH_PARENT, measure it from its specs before adding insets. if (mOrientation == VERTICAL) { @SuppressWarnings("deprecation") final boolean applyInsets = lp.height == ViewGroup.LayoutParams.FILL_PARENT; measureChildWithDecorationsAndMargin(view, spec, mainSpec, applyInsets, false); } else { //noinspection deprecation final boolean applyInsets = lp.width == ViewGroup.LayoutParams.FILL_PARENT; measureChildWithDecorationsAndMargin(view, mainSpec, spec, applyInsets, false); } final int size = mOrientationHelper.getDecoratedMeasurement(view); if (size > maxSize) { maxSize = size; } final float otherSize = 1f * mOrientationHelper.getDecoratedMeasurementInOther(view) / lp.mSpanSize; if (otherSize > maxSizeInOther) { maxSizeInOther = otherSize; } } if (flexibleInOtherDir) { // re-distribute columns guessMeasurement(maxSizeInOther, currentOtherDirSize); // now we should re-measure any item that was match parent. maxSize = 0; for (int i = 0; i < count; i++) { View view = mSet[i]; final LayoutParams lp = (LayoutParams) view.getLayoutParams(); final int spec = getChildMeasureSpec( mCachedBorders[lp.mSpanIndex + lp.mSpanSize] - mCachedBorders[lp.mSpanIndex], View.MeasureSpec.EXACTLY, 0, mOrientation == HORIZONTAL ? lp.height : lp.width, false); final int mainSpec = getChildMeasureSpec(mOrientationHelper.getTotalSpace(), mOrientationHelper.getMode(), 0, mOrientation == VERTICAL ? lp.height : lp.width, true); if (mOrientation == VERTICAL) { measureChildWithDecorationsAndMargin(view, spec, mainSpec, false, true); } else { measureChildWithDecorationsAndMargin(view, mainSpec, spec, false, true); } final int size = mOrientationHelper.getDecoratedMeasurement(view); if (size > maxSize) { maxSize = size; } } } // Views that did not measure the maxSize has to be re-measured // We will stop doing this once we introduce Gravity in the GLM layout params final int maxMeasureSpec = View.MeasureSpec.makeMeasureSpec(maxSize, View.MeasureSpec.EXACTLY); for (int i = 0; i < count; i++) { final View view = mSet[i]; if (mOrientationHelper.getDecoratedMeasurement(view) != maxSize) { final LayoutParams lp = (LayoutParams) view.getLayoutParams(); final int spec = getChildMeasureSpec( mCachedBorders[lp.mSpanIndex + lp.mSpanSize] - mCachedBorders[lp.mSpanIndex], View.MeasureSpec.EXACTLY, 0, mOrientation == HORIZONTAL ? lp.height : lp.width, false); if (mOrientation == VERTICAL) { measureChildWithDecorationsAndMargin(view, spec, maxMeasureSpec, true, true); } else { measureChildWithDecorationsAndMargin(view, maxMeasureSpec, spec, true, true); } } } result.mConsumed = maxSize; int left = 0, right = 0, top = 0, bottom = 0; if (mOrientation == VERTICAL) { if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) { bottom = layoutState.mOffset; top = bottom - maxSize; } else { top = layoutState.mOffset; bottom = top + maxSize; } } else { if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) { right = layoutState.mOffset; left = right - maxSize; } else { left = layoutState.mOffset; right = left + maxSize; } } for (int i = 0; i < count; i++) { View view = mSet[i]; LayoutParams params = (LayoutParams) view.getLayoutParams(); if (mOrientation == VERTICAL) { if (isLayoutRTL()) { right = getPaddingLeft() + mCachedBorders[params.mSpanIndex + params.mSpanSize]; left = right - mOrientationHelper.getDecoratedMeasurementInOther(view); } else { left = getPaddingLeft() + mCachedBorders[params.mSpanIndex]; right = left + mOrientationHelper.getDecoratedMeasurementInOther(view); } } else { top = getPaddingTop() + mCachedBorders[params.mSpanIndex]; bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view); } // We calculate everything with View's bounding box (which includes decor and margins) // To calculate correct layout position, we subtract margins. layoutDecorated(view, left + params.leftMargin, top + params.topMargin, right - params.rightMargin, bottom - params.bottomMargin); if (DEBUG) { Log.d(TAG, "laid out child at position " + getPosition(view) + ", with l:" + (left + params.leftMargin) + ", t:" + (top + params.topMargin) + ", r:" + (right - params.rightMargin) + ", b:" + (bottom - params.bottomMargin) + ", span:" + params.mSpanIndex + ", spanSize:" + params.mSpanSize); } // Consume the available space if the view is not removed OR changed if (params.isItemRemoved() || params.isItemChanged()) { result.mIgnoreConsumed = true; } result.mFocusable |= view.isFocusable(); } Arrays.fill(mSet, null); }
From source file:cn.ismartv.tvrecyclerview.widget.RecyclerView.java
private void recoverFocusFromState() { if (!mPreserveFocusAfterLayout || mAdapter == null || !hasFocus()) { return;//from www . j ava 2 s .co m } // only recover focus if RV itself has the focus or the focused view is hidden if (!isFocused()) { final View focusedChild = getFocusedChild(); if (focusedChild == null || !mChildHelper.isHidden(focusedChild)) { return; } } ViewHolder focusTarget = null; if (mState.mFocusedItemPosition != NO_POSITION) { focusTarget = findViewHolderForAdapterPosition(mState.mFocusedItemPosition); } if (focusTarget == null && mState.mFocusedItemId != NO_ID && mAdapter.hasStableIds()) { focusTarget = findViewHolderForItemId(mState.mFocusedItemId); } if (focusTarget == null || focusTarget.itemView.hasFocus() || !focusTarget.itemView.hasFocusable()) { return; } // looks like the focused item has been replaced with another view that represents the // same item in the adapter. Request focus on that. View viewToFocus = focusTarget.itemView; if (mState.mFocusedSubChildId != NO_ID) { View child = focusTarget.itemView.findViewById(mState.mFocusedSubChildId); if (child != null && child.isFocusable()) { viewToFocus = child; } } viewToFocus.requestFocus(); }
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 w w w .j a va 2 s. com } // 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(); } }