如何在GridView中处理卡的按钮OnClick事件?最佳做法

时间:2015-06-25 14:51:04

标签: android button gridview onclick android-cardview

我正在尝试找到处理OnClick事件的最佳解决方案,该事件由我的卡片按钮生成(请参阅下面的图片){/ 1}}。

my card and button on it

正如您所看到的,我只有一个普通的GridView,其中的单元格由我的自定义卡制成。

我只是初始化GridView和它的适配器:

GridView

您可能知道我可以轻松处理mGrid = (GridView) findViewById(R.id.grid); mAdapter = new ImageTopicsAdapter(..blah blah blah..); mGrid.setAdapter(mAdapter); 生成的OnClick事件。但只有当我点击卡片本身时它才会起作用:

GridView

我想构建与此相似的内容(请参阅下面的代码),以便我可以轻松“实现”我的mGrid.setOnItemClickListener(..blah blah blah..); 来处理我的卡片按钮Activity事件:

OnClick

最好的(干净\简单\优雅)方法是什么?

真的很感激任何帮助。亚历克斯。附:对不起我的英文:)

3 个答案:

答案 0 :(得分:2)

由于您要调度到您的活动,我建议您在活动中公开一个方法,并直接从您的点击监听器中调用它。最短的(从我的角度来看最干净):

    适配器中的
  • ,请说ArrayAdapter

    • 定义侦听点击(以避免大量匿名侦听器实例)
    • 直接向您的活动发送呼叫(因为每个视图上下文都是一项活动)
    • 上面的
    • context如果您没有手动提供其他上下文,可以视为仅ApplicationActivity

      private final MyAdapter extends ArrayAdapter implements View.OnClickListener {
          @Override
          public View getView(int position, View convertView, ViewGroup parent) {
              // inflate your card then get a reference to your button
              View card = ....;
              card.findViewById(R.id.YOUR_BUTTON_ID).setOnClickListener(this);
              return card;
          }
      
          @Override
          public void onClick(View view) {
              ApplicationActivity activity = (ApplicationActivity) view.getContext();
              if (activity != null && !activity.isFinishing()) {
                  applicationActivity.onCardButtonClick();
              }
          }
      }
      
      // in your ApplicationActivity
      public final class ApplicationActivity extends Activity {
          ...
      
          public void onCardButtonClick() {
              // deal with your click
          }
      }
      

还有其他textbook选项(在视图创建中设置监听器或活动等等),但我避免使用它们,因为它们不能完全解决任何问题。

他们只会在代码中添加更多灰尘。

正确定义的任何View上下文都指向活动(因为它也是一个上下文),它包含所有视图结构。通过这种方式,您可以快速,轻松地访问您的活动。

BTW事件总线不是一个好选择,因为事件总线非常适合一对多关系(一个调度员,许多听众)但是当一对一调用(调度员 - 监听器)密集使用时会增加更多复杂性< / p>

添加评论

您可以调整一些代码,而不是使用适配器,您可以直接从您的单元格调度。换句话说,使用适配器作为委托,创建一个匿名监听器,然后直接从您的卡片按钮到达并调用活动点击:

public final MyAdapter extends ArrayAdapter {
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // inflate your card then get a reference to your button
        View card = ....;
        card.findViewById(R.id.YOUR_BUTTON_ID).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ApplicationActivity activity = (ApplicationActivity) view.getContext();
                if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
                    applicationActivity.onCardButtonClick();
                }
            }
        });
        return card;
    }
}

添加评论 - 复合视图

要封装所有单元格逻辑,您可以从头开始创建自定义视图或使用compound view。以下示例使用复合视图:

public class ApplicationActivity extends Activity {
    ....

    public void onCardButtonClick(Cell cell) {
        // do whatever you want with the model/view
    }
}

// ViewModel instances are used in your adapter
public final class ViewModel {
    public final String description;
    public final String title;

    public ViewModel(String title, String description) {
        this.title = title != null ? title.trim() : "";
        this.description = description != null ? description.trim() : "";
    }
}

public final class Cell extends LinearLayout {
    private View button;
    private ViewModel model;

    // ViewModel is data model and is the list of items in your adapter
    public void update(ViewModel model) {
        this.model = model;
        // update your card with your model
    }

    public ViewModel getModel() {
        return model;
    }

    @Override
    protected void onAttachedToWindow() {
        button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener {
            @Override
            public void onClick(View view) {
                ApplicationActivity activity = (ApplicationActivity) view.getContext();
                if (model != null && activity != null && !activity.isFinishing() && !activity.isDestroyed() {
                    activity.onCardButtonClick(Cell.this);
                }
            }
        });
    }
}

// then your adapter `getView()` needs to inflate/create your compound view and return it
public final MyAdapter extends ArrayAdapter {
    private final List<ViewModel> items;

    public MyAdapter() {
        // update your models from outside or create on the fly, etc.
        this.items = ...;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {        
            // inflate - say it is a layout file 'cell.xml'
            convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.cell);
        }

        ((Cell) convertView).update(items.get(position));
        return convertView;
    }
}

答案 1 :(得分:1)

适配器应该处理这个问题。通常,您的适配器应该具有类似setOnOptionsClickListener(OnOptionsClickListener listener)的方法,假设我们正在讨论省略号按钮。

因此,在您的Activity / Fragment中,您使用以下代码

public interface OnOptionsClickListener {
      void onOptionsClicked(View view, PictureItem item);
}


mAdapter= new MyGridAdapter();
mAdapter.setOnOptionsClickListener(new OnOptionsClickListener() {
       public void onClick(View view, PictureItem item) {
            //process click
       }
});

并在内部适配器

public void setOnOptionsClickListener(OnOptionsClickListener l) {
    mOnOptionsClickListener = l;
}

findViewById(R.id.btn_options).setOnClickListener(new OnClickListener(){
    public void OnClick(View view) {
        mOnOptionsClickListener.onOptionsClicked(view, currentPictureItem);
    }
});

请注意。只有在OnClick()方法中需要额外参数时才需要声明界面(例如currentPictureItem以获取图片网址或项目ID)。否则,您只能使用OnClickListener。

修改 所以这是解释。 Adapter就像GridView的视图提供者一样。它创建视图并将其配置为基本状态。这就是为什么在初始化视图期间应在Adapter中设置所有点击侦听器的原因。此外,我们不希望有一个混乱的Activity嵌套Adapter,但我们希望将Adapter作为一个单独的类。这就是您通常需要创建其他界面才能访问currentItem对象以从中提取数据的原因。

答案 2 :(得分:0)

看起来没有人知道如何做到这一点。所以我在@Dimitar G.和@Konstantin Kiriushyn的帮助下找到了解决方案。谢谢你们,伙计们。

1)我将使用Compound View系统创建自己的自定义Sum(IIf([Weight]="2",[Amount],0)) AS FA_Critical ,这非常简单:CardView + LinearLayout + {{1} } + ImageView

TextView

2)然后我将在Button中创建名为public class TopicCardView extends LinearLayout { private ImageView mImage; private Button mButtonMenu; private TextView mTitle; public TopicCardView (Context context) { initializeViews(context); } private void initializeViews(Context context) { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.topic_card_view, this); } private void setTitle(...) { ... } private void setImage(...) { ... } private void setMenuClickListener(...) { ... } // and so on... } 的方法。它会生成我的自定义createListOfGridCardsFromDB(...)的列表(Activity\Fragment)(它还会将标题\图像和监听器设置为LinkedList)。

3)然后我会将CardView生成的CardView传递给LinkedList

此系统只能在app中为我的所有卡片网格使用一个适配器。它还使得无法对适配器中的点击,界面,监听器和内容做任何事情。