如何从 View.gone 恢复视图。在xml中使用'android:visibility =“gone”'后setVisibility(View.VISIBLE)不起作用

Posted

技术标签:

【中文标题】如何从 View.gone 恢复视图。在xml中使用\'android:visibility =“gone”\'后setVisibility(View.VISIBLE)不起作用【英文标题】:How to recover view from View.gone. setVisibility(View.VISIBLE) not working after using 'android:visibility="gone"' in xml如何从 View.gone 恢复视图。在xml中使用'android:visibility =“gone”'后setVisibility(View.VISIBLE)不起作用 【发布时间】:2021-12-11 10:53:11 【问题描述】:

我的问题: 在我的 xml 文件中,我在标记为assess_layout_list 的线性布局中定义了android:visibility="gone"。然后,在 course_adapter_layout 的 onClick() 整个视图中,我将可见性设置回 View.VISIBLE,这不起作用,即使在它工作之前的 Log 调用,名为assess_list_layout 的 LinearLayout 对象也不为空,并且它当我在 xml 文件中定义 visibility="invisible" 时确实有效。不过我希望它一开始就消失,点击后可见,因为这符合应用程序的设计。

这是我的 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_
    android:layout_
    android:orientation="vertical"
    android:gravity="left"
    >

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

        <ImageView
            android:layout_
            android:layout_
            android:src="@drawable/course_color_circle"/>

        <Space
            android:layout_
            android:layout_
            android:layout_weight="0.25"/>

        <TextView
            android:id="@+id/course_adapter_course_code"
            android:text="TextView1"
            android:layout_
            android:layout_
            android:layout_weight="0.5"/>

        <Space
            android:layout_
            android:layout_
            android:layout_weight="0.25"/>


        <TextView
            android:id="@+id/course_adapter_course_title"
            android:text="TextView2"
            android:layout_
            android:layout_/>

    </LinearLayout>

    <LinearLayout
        android:id="@+id/assess_list_layout"
        android:layout_
        android:layout_
        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_
            android:layout_
            android:layout_marginBottom="10dp"/>
        <LinearLayout
            android:layout_
            android:layout_
            android:orientation="horizontal">

            <Button
                android:layout_
                android:layout_
                android:layout_gravity="left"
                android:text="More" />

            <Space
                android:layout_
                android:layout_
                android:layout_weight="1"/>
            <Button
                android:layout_
                android:layout_
                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;
  

如果您需要更多信息,请告诉我。还将就完成同一件事的其他方式提出建议。谢谢你的帮助。 ~赛斯。

编辑:当assess_list_layout.setVisibility(View.VISIBLE) 在onClick 之外时,它确实有效。

进一步编辑:到目前为止我尝试过的事情都无济于事:

移动我定义 LinearLayout 组件的位置 在父视图上调用 invalidate() 使用 runOnUiThread() 在我尝试为assess_list_layout 查找ViewById 的行中将视图更改为v,它们是相同的,因此没有帮助。 在assess_list_layout 上调用requestLayout()

更新:我现在已经设法在单击 course_adapter_layout 时显示assess_list_layout 部分。现在唯一的问题是视图不再占用屏幕上的空间,它只是变成了一个可滚动的视图,可以上下滚动以查看整个视图。 此外,当我滚动到快速时,它会将视图重置为启动时的状态。

【问题讨论】:

为什么不找到你的linear layout 在你找到所有视图的地方可能会有所帮助 尝试在父视图上调用 invalidate() 使用 runOnUiThread 并放置您的assess_list_layout.setVisibility(View.VISIBLE);在其运行方法中。 @ Danish - 所以我将上下文作为构造函数的参数之一,我将其转换为 Activity,然后我用它调用 runOnUiThread,在其中我调用 setVisibility(View.VISIBLE) ,这不起作用。 就像您找到 R.id.course_adapter_layout 视图一样找到 R.id.assess_list_layout ,就像这样 LinearLayout assess_list_layout = v.findViewById(R.id.assess_list_layout); 请注意 v.findViewById 而不是 view.findViewById 。也将其移到onClick 事件之外 【参考方案1】:

1.View Visibility 不起作用

可见性不起作用,因为视图最初没有呈现。移除 xml 中的可见性并在适配器类中完全处理可见性。在“assess_list_layout”中,linerlayout 的高度可以是硬编码的,因为在这个布局中,listview 的高度已经是硬编码的。您可以硬编码为 300 并检查。这种方式将有助于视图获得初始渲染。

2。滚动问题

滚动已经可见的“assess_list_layout”视图时可能不可见。这是因为我们需要处理可见性,这个处理类似于列表视图中的复选框选择处理。希望 Course 类是模型类,在其中添加另一个名为 isSelected 的属性作为布尔值并将默认值设置为 false。请参考下面的课程课,

课程班

public class Course 
private boolean isSelected = false;

public boolean isSelected() 
        return isSelected;
    

    public void setSelected(boolean selected) 
        isSelected = selected;
    


请参考适配器类中的以下代码更改。

    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);
    
    //My Change
      // expand the view to include a new fragment
            LinearLayout assess_list_layout = view.findViewById(R.id.assess_list_layout);
    
    // 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);
    
    assess_list_layout.setVisibility(View.GONE);
    
    if (getItem().get(position).isSelected()) 
    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);
    
//My Change
    
        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);
    
           //My Change
            getItem().get(position).setSelected(true);          
            //My Change
            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);
          
        );
    
        return v;
      
    

我已评论为 My Change 以找出代码的不同之处。

【讨论】:

很好的解决方案。我添加了一个函数来切换所选内容,并且我还在“assess_list_layout.setVisibility(View.VISIBLE);”周围添加了一些选择语句您在点击侦听器中的声明以切换它是否可见。【参考方案2】:
LinearLayout assess_list_layout = view.findViewById(R.id.assess_list_layout);
assess_list_layout.setVisibility(View.VISIBLE);

在全局范围内保存它而不是它的工作,不需要使用View.VISIBLE, 保持变量唯一

不要在your XML, 中使用它,因为它会混淆。

android:visibility="gone"

XML 文件:

@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);

    LinearLayout assess_list_layout = v.findViewById(R.id.assess_list_layout);
    ListView assessment_list_view = (ListView) v.findViewById(R.id.course_adapter_assess_list);
    
    assess_list_layout.setVisibility(View.GONE);
    
    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
        assess_list_layout.setVisibility(View.VISIBLE);

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

    return v;
  

【讨论】:

这是有道理的,但我没有点击我试图设置为可见的视图,而是点击其中包含线性布局的视图。我正在尝试使assess_list_layout 可见,它包含在 course_adapter_layout 中,onClick 正在为其设置。您可能还会看到我在 onClick() 函数内部调用的 Log.i() 运行,所以我对单击/运行 onClick() 函数没有任何问题,只是对可见部分的设置。你是什​​么意思'不要在你的xml中使用它' 请检查我已经更新了我的答案检查它....! 我还是不明白你建议我做什么,请改写。 LinearLayoutassess_list_layout = v.findViewById(R.id.assess_list_layout); ListViewassessment_list_view = (ListView) v.findViewById(R.id.course_adapter_assess_list); assess_list_layout.setVisibility(View.GONE);我已更改此行以定义上述布局单击侦听器【参考方案3】:

第 1 期

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

没有复用视图,导致每次调用getView()时都会膨胀一个新视图;由于inflate()方法对IO敏感,会降低滚动的流畅度,触发卡顿。

试试这个

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

第 2 期

scorll listview 时,需要重置 itemview 状态,在 Course bean 中添加“expand”属性,点击 item set expand = true;然后添加流layout.setOnClickListener 上面的代码

v.findViewById(R.id.assess_list_layout).setVisibility( item.expand ? View.VISIBLE:View.GONE);
ListView assessment_list_view = (ListView) v.findViewById(R.id.course_adapter_assess_list);
if (item.expand) 
    AssessmentListAdapter assessAdapter = new  AssessmentListAdapter(getContext(), R.layout.assessment_adapter_view, 
   item.getAssessmentList(), item);
   assessment_list_view.setAdapter(assessAdapter);

第 3 期

getView() 方法中设置 setOnClickListener ,每次调用 getView() 都会创建一个新的 Clicker 实例。改用 listView.setOnItemClickListener()

提示:

毕竟,你应该使用 RecyclerView 而不是 ListView,这是一个强大的 UI 小部件

【讨论】:

以上是关于如何从 View.gone 恢复视图。在xml中使用'android:visibility =“gone”'后setVisibility(View.VISIBLE)不起作用的主要内容,如果未能解决你的问题,请参考以下文章

ViewStub 与 View.GONE

必须是以下之一:View.VISIBLE、View.INVISIBLE、View.GONE [重复]

Android set View.GONE 不会在列表视图中“释放”空间

Xcode 故事板等效于带有 View.GONE 的 Android LinearLayout

View.GONE 仍然在布局中占用空间

setVisibility(View.Gone) 工作,但视图仍然拥有空间