我正在尝试找到处理OnClick
事件的最佳解决方案,该事件由我的卡片按钮生成(请参阅下面的图片){/ 1}}。
正如您所看到的,我只有一个普通的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
最好的(干净\简单\优雅)方法是什么?
真的很感激任何帮助。亚历克斯。附:对不起我的英文:)
答案 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中为我的所有卡片网格使用一个适配器。它还使得无法对适配器中的点击,界面,监听器和内容做任何事情。