下面列出了android.view.View#isFocusable ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Returns a matrix of size same as the {@link CellLayout} dimension that is initialized with the
* index of the child view.
*/
// TODO: get rid of the dynamic matrix creation
public static int[][] createSparseMatrix(CellLayout layout) {
ShortcutAndWidgetContainer parent = layout.getShortcutsAndWidgets();
final int m = layout.getCountX();
final int n = layout.getCountY();
final boolean invert = parent.invertLayoutHorizontally();
int[][] matrix = createFullMatrix(m, n);
// Iterate thru the children.
for (int i = 0; i < parent.getChildCount(); i++ ) {
View cell = parent.getChildAt(i);
if (!cell.isFocusable()) {
continue;
}
int cx = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellX;
int cy = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellY;
matrix[invert ? (m - cx - 1) : cx][cy] = i;
}
return matrix;
}
protected void handleStateOnResult(LayoutChunkResult result, View view) {
if (view == null) {
return;
}
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
// Consume the available space if the view is not removed OR changed
if (params.isItemRemoved() || params.isItemChanged()) {
result.mIgnoreConsumed = true;
}
// used when search a focusable view
result.mFocusable = result.mFocusable || view.isFocusable();
}
private void getFocusableViews(View view, final List<View> focusables) {
// Not using addFocusables() or addTouchables() because of concerns with adding ViewGroup
// and not getting "clickables."
if (!(view instanceof ViewGroup) && (view != null) &&
(view.isFocusable() || view.isClickable())) {
focusables.add(view);
}
if (view instanceof ViewGroup) {
ViewGroup parent = (ViewGroup) view;
for (int i = 0; i < parent.getChildCount(); i++) {
getFocusableViews(parent.getChildAt(i), focusables);
}
}
}
/**
* Scrolls to the element with the given label (<a name...) and focuses it
* (if focusable).
*/
public void gotoLabel(String label) {
View v = label == null ? this : labels.get(label);
if (v != null) {
if (v.isFocusable()) {
v.requestFocus();
}
int y = v.getTop();
ViewParent parent = v.getParent();
while (parent instanceof View) {
if (parent instanceof ScrollView) {
((ScrollView) parent).smoothScrollTo(0, y);
break;
}
y += ((View) parent).getTop();
parent = parent.getParent();
}
}
}
/**
* 获取 View 是否可以获取焦点
* @param view {@link View}
* @return {@code true} 可获取, {@code false} 不可获取
*/
public static boolean isFocusable(final View view) {
if (view != null) {
return view.isFocusable();
}
return false;
}
@Override
public View onFocusSearchFailed(View focused, int focusDirection,
RecyclerView.Recycler recycler,
RecyclerView.State state) {
resolveShouldLayoutReverse();
if (getChildCount() == 0) {
return null;
}
final int layoutDir = convertFocusDirectionToLayoutDirection(focusDirection);
if (layoutDir == RenderState.INVALID_LAYOUT) {
return null;
}
final View referenceChild;
if (layoutDir == RenderState.LAYOUT_START) {
referenceChild = getChildClosestToStart();
} else {
referenceChild = getChildClosestToEnd();
}
ensureRenderState();
final int maxScroll = (int) (MAX_SCROLL_FACTOR * (mOrientationHelper.getEndAfterPadding() -
mOrientationHelper.getStartAfterPadding()));
updateRenderState(layoutDir, maxScroll, false, state);
mRenderState.mScrollingOffset = RenderState.SCOLLING_OFFSET_NaN;
fill(recycler, mRenderState, state, true);
final View nextFocus;
if (layoutDir == RenderState.LAYOUT_START) {
nextFocus = getChildClosestToStart();
} else {
nextFocus = getChildClosestToEnd();
}
if (nextFocus == referenceChild || !nextFocus.isFocusable()) {
return null;
}
return nextFocus;
}
private static View getFirstFocusableIconInReadingOrder(CellLayout cellLayout, boolean isRtl) {
View icon;
int countX = cellLayout.getCountX();
for (int y = 0; y < cellLayout.getCountY(); y++) {
int increment = isRtl ? -1 : 1;
for (int x = isRtl ? countX - 1 : 0; 0 <= x && x < countX; x += increment) {
if ((icon = cellLayout.getChildAt(x, y)) != null && icon.isFocusable()) {
return icon;
}
}
}
return null;
}
private static View getFirstFocusableIconInReverseReadingOrder(CellLayout cellLayout,
boolean isRtl) {
View icon;
int countX = cellLayout.getCountX();
for (int y = cellLayout.getCountY() - 1; y >= 0; y--) {
int increment = isRtl ? 1 : -1;
for (int x = isRtl ? 0 : countX - 1; 0 <= x && x < countX; x += increment) {
if ((icon = cellLayout.getChildAt(x, y)) != null && icon.isFocusable()) {
return icon;
}
}
}
return null;
}
/**
* Creates a sparse matrix that merges the icon of previous/next page and last column of
* current page. When left key is triggered on the leftmost column, sparse matrix is created
* that combines previous page matrix and an extra column on the right. Likewise, when right
* key is triggered on the rightmost column, sparse matrix is created that combines this column
* on the 0th column and the next page matrix.
*
* @param pivotX x coordinate of the focused item in the current page
* @param pivotY y coordinate of the focused item in the current page
*/
// TODO: get rid of the dynamic matrix creation
public static int[][] createSparseMatrixWithPivotColumn(CellLayout iconLayout,
int pivotX, int pivotY) {
ViewGroup iconParent = iconLayout.getShortcutsAndWidgets();
int[][] matrix = createFullMatrix(iconLayout.getCountX() + 1, iconLayout.getCountY());
// Iterate thru the children of the top parent.
for (int i = 0; i < iconParent.getChildCount(); i++) {
View cell = iconParent.getChildAt(i);
if (!cell.isFocusable()) {
continue;
}
int cx = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellX;
int cy = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellY;
if (pivotX < 0) {
matrix[cx - pivotX][cy] = i;
} else {
matrix[cx][cy] = i;
}
}
if (pivotX < 0) {
matrix[0][pivotY] = PIVOT;
} else {
matrix[pivotX][pivotY] = PIVOT;
}
return matrix;
}
public View onFocusSearchFailed(View focused, int focusDirection, Recycler recycler, State state) {
resolveShouldLayoutReverse();
if (getChildCount() == 0) {
return null;
}
int layoutDir = convertFocusDirectionToLayoutDirection(focusDirection);
if (layoutDir == Integer.MIN_VALUE) {
return null;
}
View referenceChild;
ensureLayoutState();
if (layoutDir == -1) {
referenceChild = findReferenceChildClosestToStart(recycler, state);
} else {
referenceChild = findReferenceChildClosestToEnd(recycler, state);
}
if (referenceChild == null) {
return null;
}
View nextFocus;
ensureLayoutState();
updateLayoutState(layoutDir, (int) (MAX_SCROLL_FACTOR * ((float) this.mOrientationHelper.getTotalSpace())), false, state);
this.mLayoutState.mScrollingOffset = Integer.MIN_VALUE;
this.mLayoutState.mRecycle = false;
fill(recycler, this.mLayoutState, state, true);
if (layoutDir == -1) {
nextFocus = getChildClosestToStart();
} else {
nextFocus = getChildClosestToEnd();
}
if (nextFocus == referenceChild || !nextFocus.isFocusable()) {
return null;
}
return nextFocus;
}
protected void fireOnItemClickedEvent(View view, int position) {
if (position < 0 || position > items.length)
return;
I item = items[position];
carbon.widget.RecyclerView.OnItemClickedListener<I> typeSpecificListener = (carbon.widget.RecyclerView.OnItemClickedListener<I>) onItemClickedListeners.get(item.getClass());
if (typeSpecificListener != null)
typeSpecificListener.onItemClicked(view, item, position);
if (onItemClickedListener != null)
onItemClickedListener.onItemClicked(view, item, position);
if (selectionMode != SelectionMode.NONE && view.isFocusable() && view.isClickable())
selectItem(item);
}
@Override
public View onFocusSearchFailed(View focused, int focusDirection,
RecyclerView.Recycler recycler,
RecyclerView.State state) {
resolveShouldLayoutReverse();
if (getChildCount() == 0) {
return null;
}
final int layoutDir = convertFocusDirectionToLayoutDirection(focusDirection);
if (layoutDir == RenderState.INVALID_LAYOUT) {
return null;
}
final View referenceChild;
if (layoutDir == RenderState.LAYOUT_START) {
referenceChild = getChildClosestToStart();
} else {
referenceChild = getChildClosestToEnd();
}
ensureRenderState();
final int maxScroll = (int) (MAX_SCROLL_FACTOR * (mOrientationHelper.getEndAfterPadding() -
mOrientationHelper.getStartAfterPadding()));
updateRenderState(layoutDir, maxScroll, false, state);
mRenderState.mScrollingOffset = RenderState.SCOLLING_OFFSET_NaN;
fill(recycler, mRenderState, state, true);
final View nextFocus;
if (layoutDir == RenderState.LAYOUT_START) {
nextFocus = getChildClosestToStart();
} else {
nextFocus = getChildClosestToEnd();
}
if (nextFocus == referenceChild || !nextFocus.isFocusable()) {
return null;
}
return nextFocus;
}
/**
* Determines if the supplied {@link View} is actionable for accessibility purposes.
*
* @param view The {@link View} to evaluate
* @return {@code true} if {@code view} is considered actionable for accessibility
*/
public static boolean isActionableForAccessibility(View view) {
if (view == null) {
return false;
}
return (view.isClickable() || view.isLongClickable() || view.isFocusable());
}
/**
* Focus the given view and show the soft keyboard.
* @param activity the current activity
* @param view the view to focus
*/
public static void focusAndShowKeyboard(@Nullable Activity activity, @NonNull View view) {
if (activity == null) return;
if (view.isFocusable()) {
view.requestFocus();
}
if (view instanceof EditText) {
showKeyboard(activity);
}
}
/**
* @return {@code true} if the given view has a focus.
*/
public static boolean hasFocus(View view) {
// If the container view is not focusable, we consider it always focused from
// Chromium's point of view.
return !view.isFocusable() ? true : view.hasFocus();
}
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
LayoutState layoutState, LayoutChunkResult result) {
View view = layoutState.next(recycler);
if (view == null) {
if (DEBUG && layoutState.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.
result.mFinished = true;
return;
}
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
if (layoutState.mScrapList == null) {
if (mShouldReverseLayout == (layoutState.mLayoutDirection
== LayoutState.LAYOUT_START)) {
addView(view);
} else {
addView(view, 0);
}
} else {
if (mShouldReverseLayout == (layoutState.mLayoutDirection
== LayoutState.LAYOUT_START)) {
addDisappearingView(view);
} else {
addDisappearingView(view, 0);
}
}
measureChildWithMargins(view, 0, 0);
result.mConsumed = mOrientationHelper.getDecoratedMeasurement(view);
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 (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
bottom = layoutState.mOffset;
top = layoutState.mOffset - result.mConsumed;
} else {
top = layoutState.mOffset;
bottom = layoutState.mOffset + result.mConsumed;
}
} else {
top = getPaddingTop();
bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view);
if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
right = layoutState.mOffset;
left = layoutState.mOffset - result.mConsumed;
} else {
left = layoutState.mOffset;
right = layoutState.mOffset + result.mConsumed;
}
}
// 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));
}
// Consume the available space if the view is not removed OR changed
if (params.isItemRemoved() || params.isItemChanged()) {
result.mIgnoreConsumed = true;
}
result.mFocusable = view.isFocusable();
}
protected void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
LayoutState layoutState, com.alibaba.android.vlayout.layout.LayoutChunkResult result) {
View view = layoutState.next(recycler);
if (view == null) {
if (DEBUG && layoutState.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.
result.mFinished = true;
return;
}
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
if (layoutState.mScrapList == null) {
// can not find in scrapList
if (mShouldReverseLayoutExpose == (layoutState.mLayoutDirection
== LayoutState.LAYOUT_START)) {
addView(view);
} else {
addView(view, 0);
}
} else {
if (mShouldReverseLayoutExpose == (layoutState.mLayoutDirection
== LayoutState.LAYOUT_START)) {
addDisappearingView(view);
} else {
addDisappearingView(view, 0);
}
}
measureChildWithMargins(view, 0, 0);
result.mConsumed = mOrientationHelper.getDecoratedMeasurement(view);
int left, top, right, bottom;
if (getOrientation() == VERTICAL) {
if (isLayoutRTL()) {
right = getWidth() - getPaddingRight();
left = right - mOrientationHelper.getDecoratedMeasurementInOther(view);
} else {
left = getPaddingLeft();
right = left + mOrientationHelper.getDecoratedMeasurementInOther(view);
}
if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
bottom = layoutState.mOffset;
top = layoutState.mOffset - result.mConsumed;
} else {
top = layoutState.mOffset;
bottom = layoutState.mOffset + result.mConsumed;
}
} else {
top = getPaddingTop();
bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view);
// whether this layout pass is layout form start to end or in reverse
if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
right = layoutState.mOffset;
left = layoutState.mOffset - result.mConsumed;
} else {
left = layoutState.mOffset;
right = layoutState.mOffset + result.mConsumed;
}
}
// 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));
}
// Consume the available space if the view is not removed OR changed
if (params.isItemRemoved() || params.isItemChanged()) {
result.mIgnoreConsumed = true;
}
result.mFocusable = view.isFocusable();
}
@Override
public View onFocusSearchFailed(View focused, int focusDirection,
RecyclerView.Recycler recycler, RecyclerView.State state) {
myResolveShouldLayoutReverse();
if (getChildCount() == 0) {
return null;
}
final int layoutDir = convertFocusDirectionToLayoutDirectionExpose(focusDirection);
if (layoutDir == LayoutState.INVALID_LAYOUT) {
return null;
}
View referenceChild = null;
if (layoutDir == LayoutState.LAYOUT_START) {
referenceChild = myFindReferenceChildClosestToStart(state);
} else {
referenceChild = myFindReferenceChildClosestToEnd(state);
}
if (referenceChild == null) {
if (DEBUG) {
Log.d(TAG,
"Cannot find a child with a valid position to be used for focus search.");
}
return null;
}
ensureLayoutStateExpose();
final int maxScroll = (int) (MAX_SCROLL_FACTOR * mOrientationHelper.getTotalSpace());
updateLayoutStateExpose(layoutDir, maxScroll, false, state);
mLayoutState.mScrollingOffset = LayoutState.SCOLLING_OFFSET_NaN;
mLayoutState.mRecycle = false;
mLayoutState.mOnRefresLayout = false;
fill(recycler, mLayoutState, state, true);
final View nextFocus;
if (layoutDir == LayoutState.LAYOUT_START) {
nextFocus = getChildClosestToStartExpose();
} else {
nextFocus = getChildClosestToEndExpose();
}
if (nextFocus == referenceChild || !nextFocus.isFocusable()) {
return null;
}
return nextFocus;
}
@Override
public boolean matchesSafely(View view) {
return view.isFocusable() == isFocusable;
}
void layoutChunk(Recycler recycler, State state, LayoutState layoutState, LayoutChunkResult result) {
View view = layoutState.next(recycler);
if (view == null) {
result.mFinished = true;
return;
}
int right;
int left;
int bottom;
int top;
LayoutParams params = (LayoutParams) view.getLayoutParams();
if (layoutState.mScrapList == null) {
if (this.mShouldReverseLayout == (layoutState.mLayoutDirection == -1)) {
addView(view);
} else {
addView(view, 0);
}
} else {
if (this.mShouldReverseLayout == (layoutState.mLayoutDirection == -1)) {
addDisappearingView(view);
} else {
addDisappearingView(view, 0);
}
}
measureChildWithMargins(view, 0, 0);
result.mConsumed = this.mOrientationHelper.getDecoratedMeasurement(view);
if (this.mOrientation == 1) {
if (isLayoutRTL()) {
right = getWidth() - getPaddingRight();
left = right - this.mOrientationHelper.getDecoratedMeasurementInOther(view);
} else {
left = getPaddingLeft();
right = left + this.mOrientationHelper.getDecoratedMeasurementInOther(view);
}
if (layoutState.mLayoutDirection == -1) {
bottom = layoutState.mOffset;
top = layoutState.mOffset - result.mConsumed;
} else {
top = layoutState.mOffset;
bottom = layoutState.mOffset + result.mConsumed;
}
} else {
top = getPaddingTop();
bottom = top + this.mOrientationHelper.getDecoratedMeasurementInOther(view);
if (layoutState.mLayoutDirection == -1) {
right = layoutState.mOffset;
left = layoutState.mOffset - result.mConsumed;
} else {
left = layoutState.mOffset;
right = layoutState.mOffset + result.mConsumed;
}
}
layoutDecorated(view, left + params.leftMargin, top + params.topMargin, right - params.rightMargin, bottom - params.bottomMargin);
if (params.isItemRemoved() || params.isItemChanged()) {
result.mIgnoreConsumed = true;
}
result.mFocusable = view.isFocusable();
}