如何从 Android 中的 onlistitemclick 更改各个列表视图行内小部件的可见性?
我的最终目标是更改 本教程从数组到游标。这是完整代码的链接。其要点是,您单击列表中的一行,正文会在列出的标题下方弹出,您再次点击它,正文就会消失。我不想记住注释是否打开,也不想通过视图回收来保持它打开,也不想在打开一个或任何其他我能想到的奇特排列时关闭所有其他排列。
一切都基本正常,但是当 onListItemClick 事件处理程序触发、更改可见性和 notifyDataSetChanged()
时,列表会执行奇怪的操作,包括单击两次来更改可见性,而不是重新测量自身,从而导致到列表行,每隔三次单击左右就会为自己腾出空间。
之前的尝试导致了一个完美的工作列表,除了单击时,我想要隐藏和显示的每一行中的块将隐藏和显示,并且教程中的列表工作完美,但当然在所有内容中都使用静态大小, so 只不过是一个模板。
我确信问题要么是获取附加到列表行的可见性信息,要么是在设置后更改它。
这里是 onListItemClick
:
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
((NotesCursorAdapter) getListAdapter()).toggle(position, v);
}
在 NotesCursorAdapter
内部使用切换方法:
public void toggle(int position, View view) {
ViewHolder holder = (ViewHolder) view.getTag();
holder.mExpanded[position] = !holder.mExpanded[position];
notifyDataSetChanged();
}
在 NotesCursorAdapter
外部的 ViewHolder
:
static class ViewHolder {
public TextView title;
public TextView body;
public boolean mExpanded[];
}
以及NotesCursorAdapter
本身:
class NotesCursorAdapter extends CursorAdapter {
private static final int VISIBLE = 0;
private static final int GONE = 8;
public NotesCursorAdapter(Context context, Cursor c) {
super(context, c);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.row, null, true);
ViewHolder holder = new ViewHolder();
holder.title = (TextView) rowView
.findViewById(R.id.title);
holder.body = (TextView) rowView
.findViewById(R.id.body);
holder.mExpanded = new boolean[cursor.getCount()];
rowView.setTag(holder);
return rowView;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder holder = (ViewHolder) view.getTag();
holder.title.setText(cursor.getString(cursor
.getColumnIndexOrThrow(DbAdapter.KEY_TITLE))
+ holder.mExpanded[cursor.getPosition()]);
holder.body.setText(cursor
.getString(cursor
.getColumnIndexOrThrow(DbAdapter.KEY_BODY)));
holder.body
.setVisibility(holder.mExpanded[cursor.getPosition()] ? VISIBLE : GONE);
}
public void toggle(int position, View view) {
ViewHolder holder = (ViewHolder) view.getTag();
holder.mExpanded[position] = !holder.mExpanded[position];
notifyDataSetChanged();
}
}
我不知道接下来该往哪里看。我需要创建自己的 getView()
方法吗?我能从 getItem()
中得到任何有用的东西吗?我是否完全疯狂地尝试使用这样的 listview
?
我做了更多的调查,并且代码正在运行,但是单击事件似乎会影响相反的视图。我的意思是,当您单击顶部列表项时,它会影响底部列表项。当您单击从顶部算起的第二个时,它会影响从底部算起的第二个。如果列表项的数量为奇数,则中间的列表项可以正常工作。在某种程度上,无论我使用什么方式来确定我正在影响的视图的 id,都会被翻转。列表视图是从下往上编号的吗?
My ultimate goal is to change the source of the information in this tutorial from an array to a cursor. Here is a link to the full code. The gist of it is that you click a row in the list, and the body pops open below the listed title, and you tap it again and the body is gone. I am not looking to remember if the note is open, nor am I looking to keep it open through view recycling, nor close all others when you open one or any other fancy permutation I can think of off the top of my head.
Everything mostly works, but when the onListItemClick event handler fires, changes the visibility, and notifyDataSetChanged()
s, the list does strange things, including taking two clicks to change the visibility, and not remeasuring itself, leading to the list row only making room for itself every third click or so.
A previous attempt lead to a perfectly working list, excepting that on click, the chunk in every row that I wanted to hide and show would hide and show, and the list in the tutorial works perfectly, but of course uses static sizes in everything, so is little more than a template.
I am convinced that the problem is either getting the visibility information attached to the list row or changing it once it has been set.
Here is the onListItemClick
:
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
((NotesCursorAdapter) getListAdapter()).toggle(position, v);
}
with the toggle method inside the NotesCursorAdapter
:
public void toggle(int position, View view) {
ViewHolder holder = (ViewHolder) view.getTag();
holder.mExpanded[position] = !holder.mExpanded[position];
notifyDataSetChanged();
}
the ViewHolder
outside of the NotesCursorAdapter
:
static class ViewHolder {
public TextView title;
public TextView body;
public boolean mExpanded[];
}
and the NotesCursorAdapter
itself:
class NotesCursorAdapter extends CursorAdapter {
private static final int VISIBLE = 0;
private static final int GONE = 8;
public NotesCursorAdapter(Context context, Cursor c) {
super(context, c);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.row, null, true);
ViewHolder holder = new ViewHolder();
holder.title = (TextView) rowView
.findViewById(R.id.title);
holder.body = (TextView) rowView
.findViewById(R.id.body);
holder.mExpanded = new boolean[cursor.getCount()];
rowView.setTag(holder);
return rowView;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder holder = (ViewHolder) view.getTag();
holder.title.setText(cursor.getString(cursor
.getColumnIndexOrThrow(DbAdapter.KEY_TITLE))
+ holder.mExpanded[cursor.getPosition()]);
holder.body.setText(cursor
.getString(cursor
.getColumnIndexOrThrow(DbAdapter.KEY_BODY)));
holder.body
.setVisibility(holder.mExpanded[cursor.getPosition()] ? VISIBLE : GONE);
}
public void toggle(int position, View view) {
ViewHolder holder = (ViewHolder) view.getTag();
holder.mExpanded[position] = !holder.mExpanded[position];
notifyDataSetChanged();
}
}
I am at a loss on where to look next. Do I need to make my own getView()
method? Would I get anything useful out of getItem()
? Am I totally crazy for trying to use a listview
like this?
I have done more investigating, and the code is working, but the on click events seem to be effecting the opposite views. What I mean by that, is that when you click the top list item, it effects the bottom list item. When you click the second from the top, it effects the second from the bottom. If there is an odd number of list items, the middle list item works perfectly. In some way, whatever way I am using to determine the id of the view that I am effecting is flipped. Does the listview number things from the bottom up?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我刚刚也从 API 演示的 List6 中实现了与此类似的东西。我的工作完美(尽管我在从 ImageButton 获得焦点时遇到了麻烦)。我使用了 SimpleCursorAdapter 但我想你可以使用 CursorAdapter。我对你的代码做了很多修改。
不知道为什么你还添加了 View 参数,所以我把它去掉了。
您的ViewHolder。非常简单,只是构造函数从 getView 接收参数。
这是您的自定义 ListAdapter。我不知道为什么你想将bindView和newView与ViewHolder一起使用,Android用bindView和newViews来处理这个问题。但在这种情况下您需要使用 ViewHolder,因此 getView 是必要的。
以下是如何使用 SimpleCursorAdapter 映射它
I just implemented something similar to this from List6 of API Demos as well. Mine is working perfectly (all be it I had trouble with having focus from an ImageButton). I used a SimpleCursorAdapter however I suppose you could use a CursorAdapter. I modified your code quite a bit.
Not sure why you also added the View parameter so I took that out.
Your ViewHolder. Pretty simple, just that the constructor receives parameters from your getView.
Here is your custom ListAdapter. I am not sure why you wanted to use bindView and newView with a ViewHolder, Android takes care of that with bindView and newViews. But you need to use a ViewHolder in this case so getView is necessary.
Here is how you can map it with a SimpleCursorAdapter
K,我明白了。设置显示不正确,因为 ListView 有两层:视图层和数据层。 Android 回收 ListView 中 View 的方式意味着使用哪个 View 来显示数据并不重要。因此,要使用 CursorAdapter,View 信息将进入 newView() 方法,而来自 Cursor 的数据信息将进入 bindView() 方法。这是固定的东西:
这里没有太多改变,只传递需要的内容:
视图持有者只获取构造视图所需的信息,而不是视图中的任何信息,包括可见状态:
可见状态在数组中跟踪为适配器的属性。视图信息在newView()方法中,数据信息在bindView()方法中。当notifyDataSetChanged()触发时,视图全部被回收,并且数据被重新分层。因为视图信息和数据信息是分开的,所以哪个视图与哪个数据匹配并不重要。
为了完整起见,以下是在 onCreate()、onActivityResult() 或列表需要重新加载时调用的 ListAdapter 映射的映射:
K, I got it figured out. The settings were not displaying right because a ListView has two layers: the View layer and the data layer. The way that android recycles Views in a ListView means that which View is being used to display the data does not matter. So to use a CursorAdapter, the View information goes in the newView() method, and the data information from the Cursor goes in the bindView() method. Here is the fixed stuff:
Not much changed here, only passing what is needed:
The view holder only gets information needed to construct the view, not any information in the view, including the visible state:
The visible state is tracked in an array as a property of the adapter. The view information is in the newView() method and the data information is in the bindView() method. When the notifyDataSetChanged() fires, the views are all recycled, and the data is re-layered on. Because the view info and the data info are separate, it does not matter which view gets matched up with which data.
And for completeness, here is the mapping from the ListAdapter mapping to be called in onCreate(), onActivityResult(), or whenever the list needs reloaded: