Android 开发问题:使用 AndroidTreeView 时,自定义视图无法撑满父容器

  • 在 Android 开发中,使用 AndroidTreeView 时,自定义视图无法撑满父容器
  1. 在 XML 布局文件中定义效果是这样的
  1. 实际显示效果是这样的
问题背景
(1)ViewHolder
  • android_tree_view_item_my_node.xml
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center|start"
    android:orientation="horizontal"
    android:paddingHorizontal="8dp"
    android:paddingVertical="8dp"
    android:paddingStart="16dp">

    <!-- 缩进空间,根据层级动态调整 -->
    <View
        android:id="@+id/v_space"
        android:layout_width="0dp"
        android:layout_height="1dp" />

    <!-- 展开 / 折叠图标,仅父节点显示 -->
    <ImageView
        android:id="@+id/iv_expand_icon"
        android:layout_width="24dp"
        android:layout_height="24dp"
        android:layout_marginStart="8dp"
        android:scaleType="center"
        android:src="@mipmap/arrow_right"
        android:visibility="visible" />

    <!-- 节点文本 -->
    <TextView
        android:id="@+id/tv_node_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="12dp"
        android:gravity="center_vertical"
        android:textSize="16sp" />

    <!-- 子节点数量提示,仅父节点显示 -->
    <TextView
        android:id="@+id/tv_child_count"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:paddingHorizontal="6dp"
        android:paddingVertical="2dp"
        android:textSize="16sp"
        android:visibility="gone" />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center|end"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/tv_select"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:text="选择"
            android:textSize="16sp" />
    </LinearLayout>
</LinearLayout>
  • MyNodeViewHolder.java
java 复制代码
public class MyNodeViewHolder extends TreeNode.BaseNodeViewHolder<Object> {

    private OnSelectObserver onSelectObserver;

    private ImageView ivExpandIcon;

    public MyNodeViewHolder(Context context, OnSelectObserver onSelectObserver) {
        super(context);
        this.onSelectObserver = onSelectObserver;
    }

    @Override
    public View createNodeView(TreeNode node, Object value) {
        LayoutInflater layoutInflater = LayoutInflater.from(context);
        View view = layoutInflater.inflate(R.layout.android_tree_view_item_my_node, null, false);

        View vSpace = view.findViewById(R.id.v_space);
        ivExpandIcon = view.findViewById(R.id.iv_expand_icon);
        TextView tvNodeText = view.findViewById(R.id.tv_node_text);
        TextView tvChildCount = view.findViewById(R.id.tv_child_count);
        TextView tvSelect = view.findViewById(R.id.tv_select);

        int level = node.getLevel();
        if (level > 1) {
            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) vSpace.getLayoutParams();
            int indentWidth = (level - 1) * 20;
            params.width = (int) (indentWidth * context.getResources().getDisplayMetrics().density);
            vSpace.setLayoutParams(params);
        }

        tvNodeText.setText(value.toString());

        List<TreeNode> children = node.getChildren();
        if (children != null && !children.isEmpty()) {
            ivExpandIcon.setVisibility(View.VISIBLE);
            tvChildCount.setText("(" + children.size() + ")");
            tvChildCount.setVisibility(View.VISIBLE);
        } else {
            ivExpandIcon.setVisibility(View.GONE);
            tvChildCount.setVisibility(View.GONE);
        }

        tvSelect.setOnClickListener(v -> {
            if (onSelectObserver != null) {
                onSelectObserver.onSelect(node);
            }
        });

        return view;
    }

    @Override
    public void toggle(boolean active) {
        ivExpandIcon.setImageResource(active ? R.mipmap.arrow_down : R.mipmap.arrow_right);
    }
}
(2)Activity
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".viewlinkage.AndroidTreeViewActivity">

    <LinearLayout
        android:id="@+id/ll_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" />
</androidx.constraintlayout.widget.ConstraintLayout>
java 复制代码
OnSelectObserver onSelectObserver = treeNode -> {
    Log.i(TAG, "选择了" + treeNode.getValue());
};

TreeNode rootNode = TreeNode.root();

TreeNode parentNode = new TreeNode("Parent Node");

parentNode.setViewHolder(new MyNodeViewHolder(this, onSelectObserver));

TreeNode childNode1 = new TreeNode("Child Node 1");
TreeNode childNode2 = new TreeNode("Child Node 2");
TreeNode childNode3 = new TreeNode("Child Node 3");

childNode1.setViewHolder(new MyNodeViewHolder(this, onSelectObserver));
childNode2.setViewHolder(new MyNodeViewHolder(this, onSelectObserver));
childNode3.setViewHolder(new MyNodeViewHolder(this, onSelectObserver));

parentNode.addChildren(childNode1, childNode2, childNode3);

rootNode.addChildren(parentNode);

// ----------------------------------------------------------------------------------------------------

ViewGroup container = findViewById(R.id.ll_container);

AndroidTreeView androidTreeView = new AndroidTreeView(this, rootNode);

container.addView(androidTreeView.getView());
问题跟踪
  • 给 AndroidTreeView 设置背景色,给自定义视图设置背景色
java 复制代码
...

View view = androidTreeView.getView();

view.setBackgroundColor(0x22000000);

container.addView(view);
xml 复制代码
android:background="#10FF0000"
  • 实际显示效果如下,说明自定义视图设置的 android:layout_width="match_parent" 无效
处理策略
  • 在 ViewHolder 中,给自定义视图设置布局参数,实际显示效果如下
java 复制代码
@Override
public View createNodeView(TreeNode node, Object value) {
    
    ...

    view.setLayoutParams(new ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT
    ));

    return view;
}
相关推荐
SL_staff5 小时前
告别报表重复开发:JVS-BI 模板市场的参数化继承实践
java·数据分析·数据可视化
SL_staff7 小时前
从邮箱传文档到协同流重构:企业文档协作的系统性破局实践
java·开源·github
smallyoung8 小时前
告别N+1:Spring Boot 一键数据翻译框架体系
java·后端·架构
hai_android9 小时前
把 Android App 打包成系统应用(System App)
android·kotlin·android jetpack
JMchen10 小时前
【Jetpack 内核实战 01】开篇:Jetpack 组件全家桶核心逻辑与专栏完整规划
android·kotlin·android jetpack
Bazingga10 小时前
Java16 record 完整拆解——语法、语义、限制、反射
java·后端
SL_staff11 小时前
规则联动:给工厂装上‘自动化神经反射弧’——JVS·物联网平台规则引擎实战教程
java·人工智能·物联网
骑着蜗牛撵大象32712 小时前
Linux 进程间通信之管道:从 pipe() 的内核语义到 FIFO 落地排错
android·java·linux·系统编程·fifo·管道·进程间通信
WJ.Polar12 小时前
Java封装、继承、多态
java·开发语言
ly768912 小时前
PostgreSQL 备份恢复策略:pg_basebackup、WAL 归档与 PITR 在企业 Java 系统中的落地
java·数据库·postgresql·pitr·pg_basebackup·wal 归档