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

Android中setVisibility函数失效问题求助

问题:setVisibility() 无法切换控件可见性,点击事件触发但UI无变化

我已经折腾setVisibility()好几个小时了,死活不见效。点击事件明明能正常触发,Toast提示也能正确切换(第一次点显示“Now visible”,之后交替显示提示),但那些TextView的可见性就是纹丝不动。试过加invalidate()、去掉invalidate()、换View.INVISIBLE替代View.GONE,都没用,求大佬帮忙看看!

适配器类代码

public class ExamScheduleAdapter extends ArrayAdapter<String>{ 
    private ArrayList<String> id; 
    private ArrayList<String> name; 
    private ArrayList<String> date, subject, total, passing; 
    private Activity context; 
    Button idview; 
    TextView nameview, dateview, subjectview, totalview, passview; 

    public ExamScheduleAdapter(Activity context, ArrayList<String>id, ArrayList<String>name, ArrayList<String>date) { 
        super(context, R.layout.fragment_exam_shedule, id); 
        this.id = id; 
        this.name = name; 
        this.date = date; 
        this.context = context; 
    } 

    public ExamScheduleAdapter(Activity context, ArrayList<String>id, ArrayList<String>name, ArrayList<String>date, ArrayList<String>subject, ArrayList<String>total, ArrayList<String>passing) { 
        super(context, R.layout.fragment_exam_shedule, id); 
        this.id = id; 
        this.name = name; 
        this.date = date; 
        this.subject = subject; 
        this.total = total; 
        this.passing = passing; 
        this.context = context; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent){ 
        LayoutInflater inflater = context.getLayoutInflater(); 
        View listviewItem = inflater.inflate(R.layout.list_es,null,true); 

        idview=(Button) listviewItem.findViewById(R.id.es_list_id); 
        nameview=(TextView)listviewItem.findViewById(R.id.es_list_exam_name); 
        dateview=(TextView)listviewItem.findViewById(R.id.es_list_date); 
        subjectview=listviewItem.findViewById(R.id.es_list_exam_subject); 
        totalview=listviewItem.findViewById(R.id.es_list_exam_t_marks); 
        passview=listviewItem.findViewById(R.id.es_list_exam_p_marks); 

        idview.setText(id.get(position)); 
        nameview.setText(name.get(position)); 
        dateview.setText(date.get(position)); 

        idview.setOnClickListener(new View.OnClickListener() { 
            @Override 
            public void onClick(View v) { 
                if(subjectview.getVisibility()==View.GONE){ 
                    subjectview.setVisibility(View.VISIBLE); 
                    totalview.setVisibility(View.VISIBLE); 
                    passview.setVisibility(View.VISIBLE); 
                    subjectview.invalidate(); 
                    totalview.invalidate(); 
                    passview.invalidate(); 
                    Toast.makeText(getContext(), "Now visible", Toast.LENGTH_LONG).show(); 
                } else{ 
                    subjectview.setVisibility(View.GONE); 
                    totalview.setVisibility(View.GONE); 
                    passview.setVisibility(View.GONE); 
                    subjectview.invalidate(); 
                    totalview.invalidate(); 
                    passview.invalidate(); 
                    Toast.makeText(getContext(), "Now invisible", Toast.LENGTH_LONG).show(); 
                } 
            } 
        }); 
        return listviewItem; 
    } 
} 

自定义列表布局代码

<?xml version="1.0" encoding="utf-8"?> 
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:layout_marginLeft="10dp" 
    android:layout_marginRight="10dp"> 

    <Button 
        android:id="@+id/es_list_id" 
        android:layout_height="wrap_content" 
        android:text="Exam1" 
        android:layout_row="0" 
        android:layout_column="0" 
        android:layout_columnSpan="2"/> 

    <TextView 
        android:layout_height="wrap_content" 
        android:id="@+id/es_list_exam_name" 
        android:hint="name" 
        android:layout_row="0" 
        android:layout_column="2" 
        android:layout_columnSpan="5" /> 

    <TextView 
        android:id="@+id/es_list_date" 
        android:layout_height="wrap_content" 
        android:hint="2018-07-06" 
        android:layout_row="0" 
        android:layout_column="8" 
        android:layout_columnSpan="3"/> 

    <TextView 
        android:layout_height="wrap_content" 
        android:id="@+id/es_list_exam_subject" 
        android:hint="Hindi" 
        android:layout_row="1" 
        android:layout_column="0" 
        android:visibility="gone"/> 

    <TextView 
        android:layout_height="wrap_content" 
        android:id="@+id/es_list_exam_t_marks" 
        android:hint="100" 
        android:layout_row="1" 
        android:layout_column="4" 
        android:visibility="gone"/> 

    <TextView 
        android:layout_height="wrap_content" 
        android:id="@+id/es_list_exam_p_marks" 
        android:hint="35" 
        android:layout_row="1" 
        android:layout_column="8" 
        android:visibility="gone"/> 

</GridLayout>

解决方案:问题出在ListView视图复用+全局控件引用混乱

嘿,兄弟,我一眼就瞅到问题所在了——你把控件引用存在了适配器的全局成员变量里,这在ListView复用视图的时候直接乱套!

核心问题分析

ListView的convertView是用来复用视图的,你每次调用getView都把当前Item的控件赋值给适配器的全局变量subjectview、totalview这些,当滚动列表的时候,这些变量会被后面的Item覆盖。等你点击某个按钮的时候,你操作的根本不是当前点击的那个Item里的控件,而是最后一次getView创建的那个Item的控件,所以你看不到任何变化!

修复步骤

  1. 把控件变量移到getView方法内部,不要用适配器的全局变量存这些控件引用,每个Item的控件都应该是当前listviewItem里的局部引用。
  2. 在点击事件里,通过v.getParent()获取当前点击的Item视图,然后重新findViewById拿到当前Item的控件,这样操作的才是正确的控件。

修改后的getView方法代码如下:

@Override 
public View getView(int position, View convertView, ViewGroup parent){ 
    LayoutInflater inflater = context.getLayoutInflater(); 
    View listviewItem = inflater.inflate(R.layout.list_es,null,true); 

    // 把控件改成局部变量,避免全局引用混乱
    Button idview=(Button) listviewItem.findViewById(R.id.es_list_id); 
    TextView nameview=(TextView)listviewItem.findViewById(R.id.es_list_exam_name); 
    TextView dateview=(TextView)listviewItem.findViewById(R.id.es_list_date); 

    idview.setText(id.get(position)); 
    nameview.setText(name.get(position)); 
    dateview.setText(date.get(position)); 

    idview.setOnClickListener(new View.OnClickListener() { 
        @Override 
        public void onClick(View v) { 
            // 从当前点击按钮的父视图中获取对应Item的控件
            View parentItem = (View) v.getParent();
            TextView currentSubject = parentItem.findViewById(R.id.es_list_exam_subject);
            TextView currentTotal = parentItem.findViewById(R.id.es_list_exam_t_marks);
            TextView currentPass = parentItem.findViewById(R.id.es_list_exam_p_marks);

            if(currentSubject.getVisibility()==View.GONE){ 
                currentSubject.setVisibility(View.VISIBLE); 
                currentTotal.setVisibility(View.VISIBLE); 
                currentPass.setVisibility(View.VISIBLE); 
                Toast.makeText(getContext(), "Now visible", Toast.LENGTH_LONG).show(); 
            } else{ 
                currentSubject.setVisibility(View.GONE); 
                currentTotal.setVisibility(View.GONE); 
                currentPass.setVisibility(View.GONE); 
                Toast.makeText(getContext(), "Now invisible", Toast.LENGTH_LONG).show(); 
            } 
            // 这里完全不需要invalidate(),setVisibility已经会触发UI刷新
        } 
    }); 
    return listviewItem; 
} 

额外优化建议

建议使用ViewHolder模式来优化ListView性能,避免每次getView都调用findViewById,同时彻底杜绝控件引用混乱的问题:

static class ViewHolder {
    Button idBtn;
    TextView nameTv, dateTv, subjectTv, totalTv, passTv;
}

@Override 
public View getView(int position, View convertView, ViewGroup parent){ 
    ViewHolder holder;
    if(convertView == null){
        LayoutInflater inflater = context.getLayoutInflater(); 
        convertView = inflater.inflate(R.layout.list_es,null,true); 
        holder = new ViewHolder();
        holder.idBtn = convertView.findViewById(R.id.es_list_id);
        holder.nameTv = convertView.findViewById(R.id.es_list_exam_name);
        holder.dateTv = convertView.findViewById(R.id.es_list_date);
        holder.subjectTv = convertView.findViewById(R.id.es_list_exam_subject);
        holder.totalTv = convertView.findViewById(R.id.es_list_exam_t_marks);
        holder.passTv = convertView.findViewById(R.id.es_list_exam_p_marks);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    holder.idBtn.setText(id.get(position)); 
    holder.nameTv.setText(name.get(position)); 
    holder.dateTv.setText(date.get(position)); 

    // 操作当前ViewHolder里的控件,完全不会混乱
    holder.idBtn.setOnClickListener(new View.OnClickListener() { 
        @Override 
        public void onClick(View v) { 
            if(holder.subjectTv.getVisibility()==View.GONE){ 
                holder.subjectTv.setVisibility(View.VISIBLE); 
                holder.totalTv.setVisibility(View.VISIBLE); 
                holder.passTv.setVisibility(View.VISIBLE); 
                Toast.makeText(getContext(), "Now visible", Toast.LENGTH_LONG).show(); 
            } else{ 
                holder.subjectTv.setVisibility(View.GONE); 
                holder.totalTv.setVisibility(View.GONE); 
                holder.passTv.setVisibility(View.GONE); 
                Toast.makeText(getContext(), "Now invisible", Toast.LENGTH_LONG).show(); 
            } 
        } 
    }); 
    return convertView; 
} 

这样不仅解决了你的可见性问题,还提升了列表的滚动性能,一举两得!


内容的提问来源于stack exchange,提问作者Mihir Tanksale

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 09:08:26