Не удается включить / отключить интерактивное текстовое представление внутри GridView

#android

#Android

Вопрос:

У меня есть GridView с интерактивными текстовыми представлениями в качестве элементов GridView, использующий адаптер (текстовые представления служат кнопками). Когда я нажимаю на TextView, я хочу отключить все текстовые представления в GridView — отключить в том смысле, что пользователь больше не может нажимать на них. Что я сделал, так это:

     private void toggleButtonsState(boolean enabled)
    {
        for (int i = 0; i < this.gridview.getChildCount(); i  )
        {
            this.gridview.getChildAt(i).setEnabled(enabled);            
        }
    }   
  

Однако, даже несмотря на то, что этот код вызывается с enabled == false, кнопки по-прежнему включены. Что здесь не так? Как я могу отключить другие текстовые представления? Спасибо!


Я сделал то, что вы сказали, и внедрил BaseAdapter напрямую. Однако, опять же, эти 2 метода никогда не вызываются: ни в начале, ни после notifyDataSetChanged. Действительно не знаю, что происходит. Вот код:

 public class TextViewAdapter extends BaseAdapter implements View.OnClickListener  {

@Override
public boolean areAllItemsEnabled() {
    // TODO Auto-generated method stub
    return super.areAllItemsEnabled();
}

@Override
public boolean isEnabled(int position) {
    // TODO Auto-generated method stub
    return super.isEnabled(position);
}

protected Context mContext;         

public TextViewAdapter(Context c)
{           
    this.mContext = c;      
}

@Override
public int getCount() {
    // TODO Auto-generated method stub
    return DbManager.getInstance(mContext).getCategoryCount(true);
}

@Override
public Object getItem(int arg0) {
    // TODO Auto-generated method stub
    return arg0;
}


@Override
public long getItemId(int arg0) {
    // TODO Auto-generated method stub
    return 0;
}

@Override
public View getView(int arg0, View convertView, ViewGroup arg2) {           

    final LinearLayout linearLayout;          

    if (convertView == null) {  // if it's not recycled, initialize some attributes

        LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        linearLayout = (LinearLayout)inflater.inflate(R.layout.settings_timer_textview, null);
        TextView textView = (TextView)linearLayout.findViewById(R.id.timer_textview);           
        textView.setOnClickListener(this);                          

    } else {
        linearLayout = (LinearLayout) convertView;
    }


    setCategoryView(linearLayout, arg0);    
    setControls(linearLayout, arg0);

    return linearLayout;

}

private void setControls(LinearLayout linearLayout, int index)
{
    TextView textView = (TextView)linearLayout.findViewById(R.id.timer_textview);
    Category category = getCategory(index);
    textView.setTag(category);                  
    textView.setText(category.getName());            
    textView.setTextColor(TimeManagerActivity.getForeColorByBrightness(category.getColor()));           
    textView.setBackgroundDrawable(createTextViewDrawable(category.getColor()));

    CheckBox checkbox = (CheckBox)linearLayout.findViewById(R.id.timer_checkbox);       
    checkbox.setChecked(category.getEnabled() != 0);        
    checkbox.setTag(textView.getText().toString());
}

protected Category getCategory(int index)
{
    return DbManager.getInstance(this.mContext).getCategoryByIndex(index, true);
}

protected void setCategoryView(View view, int index)
{
    // TODO Auto-generated method stub      

    TextView textView = (TextView)view.findViewById(R.id.timer_textview);       
    textView.setGravity(Gravity.CENTER);
    textView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, 40));

    CheckBox checkbox = (CheckBox)view.findViewById(R.id.timer_checkbox);
    checkbox.setVisibility(View.GONE);
}

@Override
public void onClick(View arg0)
{       
    // TODO Auto-generated method stub      
    this.notifyDataSetChanged();
}   

public void update()
{
    this.notifyDataSetChanged();
}

private StateListDrawable createTextViewDrawable(int color)
{               
    // Create a gradient for the button. Height is hardcoded to 30 (I don't know the height beforehand). 
    // I wish I could set the gradient aligned to the bottom of the button.
    final Shader shader = new LinearGradient(0, 0, 0, 0,
        new int[] { color, color },
        null, Shader.TileMode.MIRROR);          

    float[] roundedCorner = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
    ShapeDrawable normal = new ShapeDrawable(new RoundRectShape(roundedCorner, null, null));

    normal.getPaint().setShader(shader);
    normal.setPadding(3, 3, 3, 3);

    // Create a state list (I suppressed settings for pressed).             
    StateListDrawable state_list = new StateListDrawable();
    state_list.addState(new int[] { }, normal);

    return state_list;
}
  

}


Вот мой класс, производный от TextViewAdapter которого сам является производным от BaseAdapter . Мой TextViewAdapter просто определяет некоторые абстрактные методы и мало что делает. TextViewApaterMain Пытается отключить все текстовые представления в сетке, кроме того, на который был нажат. В OnClick я нажимаю TextView и хочу отключить все другие текстовые представления, поэтому я вызываю notifyDataSetChanged , но переопределения areAllItemsEnabled и isEnabled не вызываются (отладчик не останавливается в точке останова). Есть идеи? Вот некоторый код:

 public class TextViewAdapterMain extends TextViewAdapter  {

private ArrayList<Boolean> textViewStates = new ArrayList<Boolean>();

public TextViewAdapterMain(Context c) {
    super(c);


    // TODO Auto-generated constructor stub
}

@Override
public int getCount() {
    // TODO Auto-generated method stub
    return DbManager.getInstance(mContext).getCategoryCount(true);
}

@Override
protected void setCategoryView(View view, int index) {
    // TODO Auto-generated method stub      

    TextView textView = (TextView)view.findViewById(R.id.timer_textview);       
    textView.setGravity(Gravity.CENTER);
    textView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, 40));

    CheckBox checkbox = (CheckBox)view.findViewById(R.id.timer_checkbox);
    checkbox.setVisibility(View.GONE);
}   

@Override
public void onClick(View arg0) {
    // TODO Auto-generated method stub
    super.onClick(arg0);

    ((TimeManagerActivity)super.mContext).launchChronometer((TextView)arg0);


    this.notifyDataSetChanged();
}

@Override
protected Category getCategory(int index) {
    // TODO Auto-generated method stub
    return DbManager.getInstance(this.mContext).getCategoryByIndex(index, true);
}

@Override
public boolean areAllItemsEnabled() {
    return false;
}

@Override
public boolean isEnabled(int position)
{                           
    if(textViewStates.get(position))
        return true;

    return false;

}

}
  

Комментарии:

1. В документах говорится: «Интерпретация включенного состояния зависит от подкласса». Чего вы пытаетесь достичь, отключив TextViews? Вы хотите, чтобы события касания не обрабатывались? Вы хотите, чтобы они не переходили через состояния, доступные для рисования, при касании? Вы хотите, чтобы было применено определенное состояние, отображаемое в списке состояний?

2. Обратите внимание, что getChildCount() возвращает вам только те представления, которые отображаются в данный момент . Кроме того, поскольку вы меняете состояние только того, что видно, как только вы прокручиваете и getView() вызывается метод, состояние сбрасывается до того, каким оно было изначально, предположительно, включено.

Ответ №1:

Вероятно, это не сработает. Что вам нужно сделать, это переопределить две функции в вашем классе BaseAdapter следующим образом:

 @Override
public boolean areAllItemsEnabled() {
    return false;
}

@Override
public boolean isEnabled(int position) {
    if(isEnabledData[pos])
        return true;

    return false;
}
  

Это также означает, что вам нужно будет добавить способ в ваши данные / модель для отслеживания состояния выбора, в моем примере я использую простое логическое значение [] с true или false. Базовый адаптер будет использовать IsEnabled при выводе элементов сетки на экран.

Если вам нужно изменить состояние элемента, измените на model data isEnable[x] = true / false, а затем вызовите notifyDataSetChanged() на адаптере.

Комментарии:

1. Спасибо. Я реализовал оба переопределения, но по какой-то причине ни одно из них не вызывается в любое время. Я поставил точку останова, но код не вызывается. Опять же: у меня есть сетка текстовых представлений, которые служат кнопками. Как только я нажимаю на одну кнопку, я хочу, чтобы ВСЕ ОСТАЛЬНЫЕ кнопки в сетке были отключены. Как мне этого добиться? Еще раз спасибо!

2. Не могли бы вы опубликовать еще какой-нибудь код, например, ваш класс CustomAdapter, который расширяет BaseAdapter и, возможно, что вы делаете onClick? Я подозреваю, что, возможно, вы не вызываете notifyDataSetChanged, когда хотите изменить данные или используете странную реализацию BaseAdapter.