是否可以在leanback展示应用的自定义标题视图中使用多个SearchOrb按钮或其他可聚焦按钮?问题是我只能关注一个按钮......
更新
我做了什么:
有自定义标题视图类,其中包含搜索宝珠,标题文本视图,自定义宝珠和模拟时钟。
问题在于,当我尝试聚焦搜索宝珠时,焦点转移到自定义宝珠......这就是全部。仅聚焦Custom Orb。
单击Listener for main Search Orb已设置。我不知道问题出在哪里。如果需要,我可以按需发布其他代码。
感谢您的帮助!
titleview.xml:
<?xml version="1.0" encoding="utf-8"?>
<com.olegmart.smart.base.CustomTitleView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/browse_title_group"
android:padding="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
CustomTitleView.java:
package com.olegmart.smart.base;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.v17.leanback.widget.SearchOrbView;
import android.support.v17.leanback.widget.TitleViewAdapter;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.ImageView;
import com.olegmart.smart.R;
public class CustomTitleView extends RelativeLayout implements TitleViewAdapter.Provider {
private final TextView mTitleView;
private final View mAnalogClockView;
private final View mGridOrbView;
private final View mSearchOrbView;
private final TitleViewAdapter mTitleViewAdapter = new TitleViewAdapter() {
@Override
public View getSearchAffordanceView() {
return mSearchOrbView;
}
@Override
public void setTitle(CharSequence titleText) {
CustomTitleView.this.setTitle(titleText);
}
@Override
public void setBadgeDrawable(Drawable drawable) {
//CustomTitleView.this.setBadgeDrawable(drawable);
}
@Override
public void updateComponentsVisibility(int flags) {
/*if ((flags & BRANDING_VIEW_VISIBLE) == BRANDING_VIEW_VISIBLE) {
updateBadgeVisibility(true);
} else {
mAnalogClockView.setVisibility(View.GONE);
mTitleView.setVisibility(View.GONE);
}*/
int visibility = (flags & SEARCH_VIEW_VISIBLE) == SEARCH_VIEW_VISIBLE
? View.VISIBLE : View.INVISIBLE;
mSearchOrbView.setVisibility(visibility);
}
private void updateBadgeVisibility(boolean visible) {
if (visible) {
mAnalogClockView.setVisibility(View.VISIBLE);
mGridOrbView.setVisibility(View.VISIBLE);
mTitleView.setVisibility(View.VISIBLE);
} else {
mAnalogClockView.setVisibility(View.GONE);
mGridOrbView.setVisibility(View.GONE);
mTitleView.setVisibility(View.GONE);
}
}
};
public CustomTitleView(Context context) {
this(context, null);
}
public CustomTitleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomTitleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
View root = LayoutInflater.from(context).inflate(R.layout.custom_titleview, this);
mTitleView = (TextView) root.findViewById(R.id.title_tv);
mAnalogClockView = root.findViewById(R.id.clock);
mGridOrbView = root.findViewById(R.id.grid_orb);
mSearchOrbView = root.findViewById(R.id.search_orb);
}
public void setTitle(CharSequence title) {
if (title != null) {
mTitleView.setText(title);
mTitleView.setVisibility(View.VISIBLE);
mGridOrbView.setVisibility(View.VISIBLE);
mAnalogClockView.setVisibility(View.VISIBLE);
}
}
public void setBadgeDrawable(Drawable drawable) {
if (drawable != null) {
mTitleView.setVisibility(View.GONE);
mGridOrbView.setVisibility(View.VISIBLE);
mAnalogClockView.setVisibility(View.VISIBLE);
}
}
@Override
public TitleViewAdapter getTitleViewAdapter() {
return mTitleViewAdapter;
}
}
custom_titleview.xml:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v17.leanback.widget.SearchOrbView
android:id="@+id/search_orb"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:transitionGroup="true"
android:layout_gravity="center_vertical|start"
android:layout_marginTop="8dp"
android:paddingStart="48dp"
android:focusable="true"
android:nextFocusRight="@+id/grid_orb"
/>
<AnalogClock
android:id="@+id/clock"
android:layout_width="80dp"
android:layout_height="80dp"
android:padding="6dp"
android:layout_alignParentEnd="true"
android:layout_gravity="center_vertical|end"
android:layout_marginEnd="24dp" />
<android.support.v17.leanback.widget.SearchOrbView
android:id="@+id/grid_orb"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="24dp"
android:layout_centerVertical="true"
android:layout_toStartOf="@id/clock"
android:nextFocusLeft="@+id/search_orb"
android:focusable="true"
/>
<TextView
android:id="@+id/title_tv"
android:textAppearance="@android:style/TextAppearance.Large"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:layout_centerVertical="true"
android:layout_toStartOf="@id/grid_orb" />
</merge>
答案 0 :(得分:3)
Teng-pao Yu是正确的.... BrowseFragment中的OnFocusSearchListener是未按预期发生焦点更改的原因。
首先有点背景......
当进行焦点搜索时,它将首先调用当前ViewGroup中的focusSearch方法。在这种情况下,当搜索orb具有当前焦点,并且用户按下d-pad以聚焦在不同的方向时,焦点搜索的第一个回调将在CustomTitleView类中。只有 后,CustomTitleView会将focusSearch传播给调用BrowseFragment的OnFocusSearchListener的父级。
这里的真正问题是(在撰写本文时),Leanback BrowseFragment的OnFocusSearchListener已经过编码,因此您添加到CustomTitleLayout的其他视图实际上永远无法获得焦点。
但是,有一种方法可以将其他子视图集中在CustomTitleLayout ....
覆盖CustomTitleLayout中的focusSearch方法,如下面的代码示例所示,并返回自定义标题布局中存在的可聚焦视图(而不是返回到super.focusSearch)。
请注意,此代码取决于在CustomTitleView的子项上设置nextFocusLeft和nextFocusRight属性。此外,子视图必须是可聚焦视图(按钮...等)。如果默认情况下子视图不可聚焦(类似于TextView),则必须手动启用视图,以便通过android:focusable="true"
的XML或带有View.setFocusable(true)
的代码进行聚焦。
public class CustomTitleView extends RelativeLayout implements TitleViewAdapter.Provider {
.... all your custom view stuff....
@Override
public View focusSearch(View focused, int direction) {
View nextFoundFocusableViewInLayout = null;
// Only concerned about focusing left and right at the moment
if (direction == View.FOCUS_LEFT || direction == View.FOCUS_RIGHT) {
// Try to find the next focusable item in this layout for the supplied direction
int nextFoundFocusableViewInLayoutId = -1;
switch(direction) {
case View.FOCUS_LEFT :
nextFoundFocusableViewInLayoutId = focused.getNextFocusLeftId();
break;
case View.FOCUS_RIGHT :
nextFoundFocusableViewInLayoutId = focused.getNextFocusRightId();
break;
}
// View id for next focus direction found....get the View
if (nextFoundFocusableViewInLayoutId != -1) {
nextFoundFocusableViewInLayout = findViewById(nextFoundFocusableViewInLayoutId);
}
}
// Return the found View in the layout if it's focusable
if (nextFoundFocusableViewInLayout != null && nextFoundFocusableViewInLayout.isFocusable()) {
return nextFoundFocusableViewInLayout;
} else {
// No focusable view found in layout...propagate to super (should invoke the BrowseFrameLayout.OnFocusSearchListener
return super.focusSearch(focused, direction);
}
}
@Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
// Gives focus to the SearchOrb first....if not...default to normal descendant focus search
return getSearchAffordanceView().requestFocus() || super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
}
}
答案 1 :(得分:1)
在BrowseFrameLayout
中,正常的focusSearch()被OnFocusSearchListener
拦截:
@Override
public View focusSearch(View focused, int direction) {
if (mListener != null) {
View view = mListener.onFocusSearch(focused, direction);
if (view != null) {
return view;
}
}
return super.focusSearch(focused, direction);
}
并且很可能在您的情况下返回null,请参阅:
private final BrowseFrameLayout.OnFocusSearchListener mOnFocusSearchListener =
new BrowseFrameLayout.OnFocusSearchListener() {
@Override
public View onFocusSearch(View focused, int direction) {
// if headers is running transition, focus stays
if (mCanShowHeaders && isInHeadersTransition()) {
return focused;
}
if (DEBUG) Log.v(TAG, "onFocusSearch focused " + focused + " + direction " + direction);
if (getTitleView() != null && focused != getTitleView() &&
direction == View.FOCUS_UP) {
return getTitleView();
}
if (getTitleView() != null && getTitleView().hasFocus() &&
direction == View.FOCUS_DOWN) {
return mCanShowHeaders && mShowingHeaders ?
mHeadersFragment.getVerticalGridView() : mMainFragment.getView();
}
boolean isRtl = ViewCompat.getLayoutDirection(focused) == View.LAYOUT_DIRECTION_RTL;
int towardStart = isRtl ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
int towardEnd = isRtl ? View.FOCUS_LEFT : View.FOCUS_RIGHT;
if (mCanShowHeaders && direction == towardStart) {
if (isVerticalScrolling() || mShowingHeaders || !isHeadersDataReady()) {
return focused;
}
return mHeadersFragment.getVerticalGridView();
} else if (direction == towardEnd) {
if (isVerticalScrolling()) {
return focused;
} else if (mMainFragment != null && mMainFragment.getView() != null) {
return mMainFragment.getView();
}
return focused;
} else if (direction == View.FOCUS_DOWN && mShowingHeaders) {
// disable focus_down moving into PageFragment.
return focused;
} else {
return null;
}
}
};
一个非常丑陋的解决方法是扩展您自己的BrowseFragment
或BrowseFrameLayout
答案 2 :(得分:0)
如果您想对屏幕上的可聚焦项目进行更多自定义,您可能需要查看the docs中的nextFocusForward
和类似的XML属性。