You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现RowsSupportFragment中仅聚焦行显示GridView的效果

解决选中行才显示横向GridView的焦点问题

我之前也遇到过类似的需求,你现在的问题根源在于:当把GridView设置为GONE时,系统的焦点遍历路径被直接破坏了——行失去了它的子焦点区域,导致上下行切换或者行内左右切换时,焦点无法正确找到可聚焦的元素。下面是我验证过的解决方案,分步骤来:

1. 修改可见性切换逻辑,加入手动焦点管理

不要直接切换可见性就完事,要在显示/隐藏GridView时手动处理焦点转移,确保焦点始终有可依附的元素:

@Override 
protected void onSelectLevelChanged(RowPresenter.ViewHolder holder) { 
    super.onSelectLevelChanged(holder); 
    ListRowPresenter.ViewHolder vh = (ListRowPresenter.ViewHolder) holder; 
    GridView gridView = vh.getGridView();
    
    if (vh.isSelected()){ 
        gridView.setVisibility(View.VISIBLE);
        // 行选中后,延迟将焦点移到GridView的第一个元素(确保布局完成)
        gridView.post(() -> {
            if (gridView.getAdapter() != null && gridView.getAdapter().getCount() > 0) {
                gridView.requestFocusFromTouch();
            }
        });
    } else { 
        // 隐藏GridView前,先把焦点移回行本身
        vh.getView().requestFocus();
        gridView.setVisibility(View.GONE); 
    } 
}

2. 重写Presenter的焦点相关方法,加固焦点流转

还需要重写ListRowPresenter的两个核心方法,处理焦点在选中/非选中状态下的流转逻辑:

@Override
public void onViewFocused(ViewHolder holder, View view) {
    super.onViewFocused(holder, view);
    ListRowPresenter.ViewHolder vh = (ListRowPresenter.ViewHolder) holder;
    // 确保焦点行的GridView始终可见
    if (vh.isSelected()) {
        vh.getGridView().setVisibility(View.VISIBLE);
    }
}

@Override
public void onViewSelected(ViewHolder holder, boolean selected) {
    super.onViewSelected(holder, selected);
    ListRowPresenter.ViewHolder vh = (ListRowPresenter.ViewHolder) holder;
    GridView gridView = vh.getGridView();
    
    if (!selected) {
        vh.getView().requestFocus();
        gridView.setVisibility(View.GONE);
    } else {
        gridView.setVisibility(View.VISIBLE);
        // 延迟请求焦点,避免布局未完成导致焦点丢失
        gridView.postDelayed(() -> {
            if (gridView.getAdapter() != null && gridView.getAdapter().getCount() > 0) {
                gridView.requestFocus();
            }
        }, 100);
    }
}

3. 确保行布局本身可聚焦

检查你的行布局(不管是系统默认的lb_list_row还是自定义布局),必须保证根布局能接收焦点,这样GridView隐藏时,行本身依然可以作为焦点载体:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:orientation="vertical">
    
    <!-- 行标题 -->
    <TextView
        android:id="@+id/row_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:padding="8dp"/>
    
    <!-- 自定义焦点感知的GridView -->
    <com.yourpackage.FocusAwareGridView
        android:id="@+id/grid_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:numColumns="auto_fit"
        android:columnWidth="120dp"
        android:visibility="gone"/>
</LinearLayout>

4. 自定义GridView处理焦点边界

为了解决行内左切换焦点的问题,我们需要自定义一个GridView,当焦点在第一个元素时按左方向键,自动把焦点移回行本身:

public class FocusAwareGridView extends GridView {
    public FocusAwareGridView(Context context) {
        super(context);
    }

    public FocusAwareGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && getSelectedItemPosition() == 0) {
            // 左移到边界时,焦点交给父布局(行)
            if (getParent() != null) {
                getParent().requestFocus();
                return true;
            }
        }
        return super.onKeyDown(keyCode, event);
    }
}

按照上面的步骤处理后,就能完美实现「默认隐藏行内GridView,选中时才显示」的效果,同时保证焦点在行间、行内的切换完全正常。

内容的提问来源于stack exchange,提问作者V. Denis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:31:14