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

Android中xml设android:visibility="gone"后调用setVisibility(View.VISIBLE)不生效如何解决

问题描述

我在xml文件中给id为assess_list_layout的LinearLayout设置了android:visibility="gone"属性,之后在根视图course_adapter_layout的onClick()回调中将该布局的可见性改为View.VISIBLE,但操作不生效。代码前的Log可以正常打印,assess_list_layout的LinearLayout对象也不为空,将xml中的visibility属性改为invisible时操作可以正常生效,但我的需求是初始状态下布局为gone,点击后变为visible,符合应用设计要求。

补充信息

  • 将assess_list_layout.setVisibility(View.VISIBLE)放在onClick回调外时可以正常生效
  • 已经尝试过以下方案均未解决问题:
    • 调整LinearLayout组件的定义位置
    • 调用父视图的invalidate()方法
    • 使用runOnUiThread()包裹操作代码
    • 查找assess_list_layout时将findViewById的调用主体从view改为v(二者为同一对象,无效果)
    • 调用assess_list_layout的requestLayout()方法
  • 最新进展:已经实现点击course_adapter_layout时显示assess_list_layout区域的功能,剩余两个问题:
    1. 展开的视图不会额外占用屏幕空间,需要上下滚动才能查看完整内容
    2. 快速滚动列表时,视图会重置为应用启动时的初始状态

相关代码

course_adapter_view.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/course_adapter_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:gravity="left"
    >

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginHorizontal="20dp"
        android:layout_marginTop="20dp"
        android:padding="15dp"
        android:elevation="2dp"
        android:background="@drawable/course_header_background">

        <ImageView
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:src="@drawable/course_color_circle"/>

        <Space
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="0.25"/>

        <TextView
            android:id="@+id/course_adapter_course_code"
            android:text="TextView1"
            android:layout_width="wrap_content"
            android:layout_height="20dp"
            android:layout_weight="0.5"/>

        <Space
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="0.25"/>


        <TextView
            android:id="@+id/course_adapter_course_title"
            android:text="TextView2"
            android:layout_width="wrap_content"
            android:layout_height="20dp"/>

    </LinearLayout>

    <LinearLayout
        android:id="@+id/assess_list_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_marginRight="40dp"
        android:layout_marginLeft="40dp"
        android:background="@drawable/course_body_background"
        android:padding="20dp"
        android:visibility="gone"
        >


        <ListView
            android:id="@+id/course_adapter_assess_list"
            android:layout_width="match_parent"
            android:layout_height="250dp"
            android:layout_marginBottom="10dp"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="left"
                android:text="More" />

            <Space
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"/>
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="left"
                android:text="New"/>

        </LinearLayout>


    </LinearLayout>


</LinearLayout>

CourseListAdapter.java

package com.example.schoolplanner2.adapters;


public class CourseListAdapter extends ArrayAdapter<Course> {
  private static final String TAG = "CourseListAdapter";

  private Context context;
  int mResource;

  public CourseListAdapter(@NonNull Context context, int resource, @NonNull ArrayList<Course> objects) {
    super(context, resource, objects);
    this.context = context;
    mResource = resource;
    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
    // get info
    String course_code = getItem(position).getCourseCode();
    Double course_grade = getItem(position).getCurrentGrade();

    // make inflater and inflate the layout
    LayoutInflater inflater = LayoutInflater.from(context);
    View v = inflater.inflate(mResource, parent, false);


    TextView tv_course_code = v.findViewById(R.id.course_adapter_course_code);
    TextView tv_course_title = v.findViewById(R.id.course_adapter_course_title);

    tv_course_code.setText(course_code);
    tv_course_title.setText(String.valueOf(course_grade));

    // add on click to each list view element
    LinearLayout layout = v.findViewById(R.id.course_adapter_layout);
    layout.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        Log.i(TAG, "List view element has been clicked " + course_code);

       
        // expand the view to include a new fragment
        LinearLayout assess_list_layout = view.findViewById(R.id.assess_list_layout);
        assess_list_layout.setVisibility(View.VISIBLE);

        // get the list view and add each course to the course view
        ListView assessment_list_view = (ListView) view.findViewById(R.id.course_adapter_assess_list);
        AssessmentListAdapter assessAdapter = new AssessmentListAdapter(getContext(), R.layout.assessment_adapter_view, getItem(position).getAssessmentList(), getItem(position));
        assessment_list_view.setAdapter(assessAdapter);
      }
    });

    return v;
  }
}

解决方案

针对剩余两个问题的处理方案

1. 展开后视图不额外占用空间、只能滚动查看的问题

该问题是外层ListView的item高度测量逻辑导致:默认ListView不会自动重新测量已渲染item的高度,动态改变item内部布局可见性时,需要手动通知ListView重新测量当前item高度,在设置assess_list_layout.setVisibility(View.VISIBLE)后添加以下代码即可:

assess_list_layout.setVisibility(View.VISIBLE);
// 新增代码触发item重新测量
v.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
ViewGroup.LayoutParams params = v.getLayoutParams();
params.height = v.getMeasuredHeight();
v.setLayoutParams(params);

如果替换为 RecyclerView 实现列表,仅需要调用notifyItemChanged(position)即可自动更新item高度,无需手动测量。

2. 快速滚动列表时视图重置的问题

该问题是ListView的复用机制导致:滑出屏幕的item会被回收复用,点击时设置的可见性状态没有被持久化存储,复用时会回到xml定义的gone初始状态。
解决方法是给Course类新增状态存储字段,记录item的展开状态:

  1. 在Course类中新增private boolean isExpanded = false;,同时添加对应的getter和setter方法
  2. 在getView()方法中,根据当前Course对象的isExpanded状态设置布局可见性:
LinearLayout assess_list_layout = v.findViewById(R.id.assess_list_layout);
ListView assessment_list_view = v.findViewById(R.id.course_adapter_assess_list);
if (getItem(position).isExpanded()) {
    assess_list_layout.setVisibility(View.VISIBLE);
    AssessmentListAdapter assessAdapter = new AssessmentListAdapter(getContext(), R.layout.assessment_adapter_view, getItem(position).getAssessmentList(), getItem(position));
    assessment_list_view.setAdapter(assessAdapter);
} else {
    assess_list_layout.setVisibility(View.GONE);
}
  1. 在点击事件中更新状态并通知适配器刷新:
@Override
public void onClick(View view) {
    Log.i(TAG, "List view element has been clicked " + course_code);
    getItem(position).setExpanded(!getItem(position).isExpanded());
    notifyDataSetChanged();
}

优化建议

可以使用RecyclerView替换外层的ListView,RecyclerView复用机制更灵活,自带item局部刷新、过渡动画等能力,实现折叠展开效果的成本更低,也不会出现原生ListView的高度测量异常问题。


内容的提问来源于stack exchange,提问作者Seth Harlaar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 16:24:03