我已经在我的listView中实现了ViewHolder和ConvertView。我的listView由一个自定义适配器填充,其中包含一个预订列表。当我单击一个项目时,一个不可见的布局从右向左滑动,以显示按钮。我可以通过单击一个关闭按钮来关闭这个覆盖布局,以便它再次被隐藏。在这个覆盖布局上,我有一个删除按钮,它使我能够删除该项目。到目前为止一切都很好。当我擦除一个项目时,该项目会按预期消失,然后重新加载适配器。下面的项目占据已删除项目的位置,但仍然不可见。我知道它在这里,因为我仍然可以点击该项目来触发覆盖视图。所以覆盖视图是可见的,但项目不可见。我不知道为什么会发生这种情况。我怀疑ViewHolder应对这种行为负责,但我找不到解决办法。谢谢你的帮助。
请点击此处观看视频:http://youtu.be/KBGEvbUq-V0
我的预订类别:
public class BookingsListFragment extends Fragment {
private final String SHOP_NAME_KEY = "ShopName";
private final String SHOP_ADDRESS_KEY = "ShopAddress";
public static int mSelectedItem = -1;
private static ListView mBookingsListView;
private static BookingsListViewAdapter mBookingsListViewAdapter;
private static ArrayList<Booking> mBookings;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(getActivity()));
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bookings_list_fragment, container, false);
configureListView(view);
return view;
}
@Override
public void onResume() {
super.onResume();
mSelectedItem = -1;
}
private void configureListView(View view) {
mBookings = BookingsHandler.getBookings();
mBookingsListView = (ListView) view.findViewById(R.id.bookingsListView);
mBookingsListViewAdapter = new BookingsListViewAdapter();
mBookingsListView.setAdapter(mBookingsListViewAdapter);
mBookingsListView.setTextFilterEnabled(true);
}
public static void updateBookingsListView(ArrayList<Booking> mBookingsList){
mBookings = mBookingsList;
mBookingsListViewAdapter.notifyDataSetChanged();
}
static class ViewHolder {
LinearLayout bookingItemLL;
RelativeLayout optionsOverlay;
TextView productName;
TextView price;
TextView shopName;
TextView endDate;
ImageView productImage;
LinearLayout placeholderLL;
Button cancelBooking;
Button displayDirections;
Button callShop;
ImageView discardOverlay;
}
private class BookingsListViewAdapter extends BaseAdapter {
private static final int TYPE_ITEM = 0;
private static final int TYPE_PLACEHOLDER = 1;
@Override
public int getCount() {
if (mBookings != null)
return mBookings.size();
else
return 1;
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
// Define a way to determine which layout to use
if (mBookings != null && mBookings.size() > 0)
return TYPE_ITEM;
else
return TYPE_PLACEHOLDER;
}
@Override
public int getViewTypeCount() {
return 2; // Number of different layouts
}
@Override
public View getView(final int position, View convertView, ViewGroup viewGroup) {
int type = getItemViewType(position);
final ViewHolder holder;
if(convertView == null) {
holder = new ViewHolder();
switch (type){
case TYPE_ITEM :
convertView = LayoutInflater.from(getActivity()).inflate(R.layout.bookings_item, null);
holder.bookingItemLL = (LinearLayout) convertView.findViewById(R.id.bookingItemLL);
holder.optionsOverlay = (RelativeLayout) convertView.findViewById(R.id.bookingOptionsOverlay);
holder.productName = (TextView) convertView.findViewById(R.id.bookingProductName);
holder.price = (TextView) convertView.findViewById(R.id.bookedProductPrice);
holder.shopName = (TextView) convertView.findViewById(R.id.bookingShopName);
holder.endDate = (TextView) convertView.findViewById(R.id.bookingEndDate);
holder.productImage = (ImageView) convertView.findViewById(R.id.bookedProductImage);
holder.displayDirections = (Button) convertView.findViewById(R.id.routeShop);
holder.cancelBooking = (Button) convertView.findViewById(R.id.cancelBooking);
holder.callShop = (Button) convertView.findViewById(R.id.callShop);
holder.discardOverlay = (ImageView) convertView.findViewById(R.id.discardOverlay);
break;
case TYPE_PLACEHOLDER :
convertView = LayoutInflater.from(getActivity()).inflate(R.layout.booking_placeholder, null);
holder.placeholderLL = (LinearLayout) convertView.findViewById(R.id.placeHolderLL);
break;
}
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
if(type == 0) {
if(position == mSelectedItem){
holder.optionsOverlay.setVisibility(View.VISIBLE);
configureOverlayButtons(holder);
}
holder.bookingItemLL.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mSelectedItem != position && mSelectedItem != -1){
View item = mBookingsListView.getChildAt(mSelectedItem - mBookingsListView.getFirstVisiblePosition());
if(item != null){
RelativeLayout overlayOptions = (RelativeLayout) item.findViewById(R.id.bookingOptionsOverlay);
overlayOptions.setVisibility(View.GONE);
}
}
Animation slideInAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.booking_options_overlay_animation);
holder.optionsOverlay.startAnimation(slideInAnimation);
holder.optionsOverlay.setVisibility(View.VISIBLE);
mSelectedItem = position;
configureOverlayButtons(holder);
}
});
final Booking booking = mBookings.get(position);
holder.productName.setText(booking.getName().toUpperCase());
holder.price.setText("Prix lors de la réservation : " + String.format("%.2f", Float.valueOf(booking.getPrice())) + " €");
holder.shopName.setText(booking.getShopName());
holder.endDate.setText(booking.getEndDate());
holder.productImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
DisplayImageOptions options = new DisplayImageOptions.Builder()
.showImageOnLoading(R.drawable.product_placeholder)
.showImageOnFail(R.drawable.product_no_image_placeholder)
.cacheInMemory(true)
.cacheOnDisk(true)
.build();
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.displayImage(BeeWylApiClient.getImageUrl(booking.getImageURL()),holder.productImage, options);
}
if(type == 1){
holder.placeholderLL.setLayoutParams(BeeWylHelper.getPlaceHolderSizeForFreeScreenSpace(getActivity(),0));
}
return convertView;
}
private void configureOverlayButtons(final ViewHolder holder){
holder.cancelBooking.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder ab = new AlertDialog.Builder(getActivity());
ab.setMessage("Annuler la réservation ?").setPositiveButton("Oui", dialogClickListener)
.setNegativeButton("Non", dialogClickListener).show();
}
});
holder.displayDirections.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
launchMapActivity();
}
});
holder.callShop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
launchDialer();
}
});
holder.discardOverlay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Animation hideOverlayAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.booking_overlay_dismiss);
holder.optionsOverlay.startAnimation(hideOverlayAnimation);
holder.optionsOverlay.setVisibility(View.GONE);
holder.optionsOverlay.clearAnimation();
}
});
}
private void sendCancelBookingToAPI(String id_booking) throws JsonProcessingException {
BeeWylApiClient.cancelBooking(id_booking, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int i, Header[] headers, byte[] bytes) {
try {
Log.v("xdebug CANCEL", new String(bytes, "UTF_8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(int i, Header[] headers, byte[] bytes, Throwable throwable) {
Log.v("xdebug CANCEL ERROR", String.valueOf(throwable));
}
});
}
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which){
case DialogInterface.BUTTON_POSITIVE:
Animation hideOverlayAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.booking_overlay_dismiss);
mBookingsListView.getChildAt(mSelectedItem-mBookingsListView.getFirstVisiblePosition()).startAnimation(hideOverlayAnimation);
new Handler().postDelayed(new Runnable() {
public void run() {
try {
sendCancelBookingToAPI(mBookings.get(mSelectedItem).getId());
} catch (JsonProcessingException e) {
e.printStackTrace();
}
mBookings.remove(mSelectedItem);
mSelectedItem = -1;
updateBookingsListView(mBookings);
}
}, hideOverlayAnimation.getDuration());
break;
case DialogInterface.BUTTON_NEGATIVE:
dialog.cancel();
break;
}
}
};
}
}
该物品膨胀了:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
>
<LinearLayout
android:id="@+id/bookingItemLL"
android:layout_width="match_parent"
android:layout_height="151dp"
android:orientation="horizontal"
android:weightSum="100"
android:background="@drawable/product_item_rectangle"
>
<ImageView
android:id="@+id/bookedProductImage"
android:layout_width="150dp"
android:layout_height="150dp"
android:background="@android:color/white"
android:src="@drawable/nivea"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_vertical"
>
<TextView
android:id="@+id/bookingProductName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="BRUME NIVEA"
android:textColor="@color/ProductsBlue"
android:textSize="16dp"
android:textStyle="bold"
/>
<TextView
android:id="@+id/bookedProductPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Prix lors de la réservation : 24,90€"
android:textSize="12dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp"
android:textColor="@color/ProductsBlue" android:layout_gravity="left"
/>
<TextView
android:id="@+id/bookingShopName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp"
android:text="Magasin"
android:textSize="12dp"
android:textColor="@color/ProductsBlue"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp"
android:text="Réservé jusqu'au"
android:textSize="12dp"
android:textColor="@color/ProductsBlue" />
<TextView
android:id="@+id/bookingEndDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="-"
android:textSize="12dp"
android:textColor="@color/ProductsBlue" />
</LinearLayout>
</LinearLayout>
<RelativeLayout android:id="@+id/bookingOptionsOverlay"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="#EEFFFFFF"
android:visibility="gone">
<ImageView
android:id="@+id/discardOverlay"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:src="@drawable/ic_discard_booking_overlay"
android:padding="5dp"
/>
<Button android:id="@+id/callShop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="APPELER"
android:layout_weight="1"
android:background="#00000000"
android:drawableTop="@drawable/booking_call"
android:textColor="@color/ProductsBlue"
android:textSize="14dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:drawablePadding="20dp"
android:layout_marginLeft="20dp"
/>
<Button android:id="@+id/cancelBooking"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ANNULER"
android:layout_weight="1"
android:background="#00000000"
android:drawableTop="@drawable/booking_cancel"
android:textColor="@color/ProductsBlue"
android:textSize="14dp"
android:layout_centerInParent="true"
android:drawablePadding="20dp"
/>
<Button android:id="@+id/routeShop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ITINERAIRE"
android:layout_weight="1"
android:background="#00000000"
android:drawableTop="@drawable/booking_route"
android:textColor="@color/ProductsBlue"
android:textSize="14dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:drawablePadding="20dp"
android:layout_marginRight="20dp"
/>
</RelativeLayout>
</RelativeLayout>
您的问题来自于重复使用convertView。
当前一个项目被点击时,OnClickListener被触发,在那里该项目的可见性被设置为消失。后来,这个视图被回收并作为convertView传递给getView()。因为您正在重新使用它而不重置所做的任何更改,所以您现在正在处理一个不处于已知状态的新项目的视图。您应该确保在使用convertView之前撤消任何更改。
快速解决方法是不重用传递给getView()的convertView。因此,在您检查是否可以重用convertView的代码中:
if(convertView == null)
破坏检查只是为了看看事情是否开始工作:
if(true)
如果这样做的伎俩,你可能会想修复它。
在上述检查的else子句中,您将从标记中获取项目保持器。还可以撤消OnClickListeners可能进行的任何更改。您希望从已知状态的新项目的视图开始。您应该显式初始化它。例如:
if(convertView == null) {
// ... snipped all the initialization ...
} else {
holder = (ViewHolder)convertView.getTag();
convertView.setVisibility(View.VISIBLE);
}
更新
我从来没有使用过“异构”适配器,所以我真的不能回答为什么“convertView重用覆盖视图而不是我的项目的根视图。”Adapter.getView()的Android开发人员文档介绍了< code>convertView参数:
如果可能,重用旧视图。注意:在使用之前,您应该检查此视图是否为非空且类型是否合适。如果无法转换此视图以显示正确的数据,则此方法可以创建新视图。异构列表可以指定其视图类型的数量,以便此视图始终属于正确的类型(请参见获取视图类型计数 () 和获取Item视图类型(int))。
强调的部分说您不能依赖系统向您传递正确类型的转换视图,而最后一句话则相反(正如我所读到的)。
基本上,我不知道为什么它不起作用。我猜在测试中,你检查你是否必须自己膨胀一个新视图
if(convertView == null)
您还应该检查它是否是正确的视图:
if(convertView == null || getItemViewTypeFromView(convertView) != type)
其中< code > getItemViewTypeFromView()是这样的:
private int getItemViewTypeFromView(View view) {
switch (view.getId()) {
case R.id.item_layout_root:
return TYPE_ITEM;
case R.id.placeholder_layout_root:
return TYPE_PLACEHOLDER;
default:
throw new UnsupportedOperationException();
}
}
在项目和占位符布局中,给根元素一个id,以便您区分它们。所以像这样:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_layout_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingLeft="5dp"
android:paddingRight="5dp" >
... snipped the elements that make up the body of the layout ...
</RelativeLayout>
我没有试过上面的,所以我希望它对你有用。
祝你好运!
我正在使用RecyclerView,并有一些动画,我可以在ViewHolder项目中放大一个相对布局。 注意:它不是添加/删除/插入动画。当用户在 ViewHolder 项中交互时,它将启动。因此,我在这里没有使用ItemAnimator。 动画工作正常,但它会在某个随机视图项中重新出现(最终状态)。我知道这是由于物品的重复使用,我也在清除动画,但这没有帮助。 我在节目里做这个 在onViewDe
首先,相关链接:http://www.songho.ca/opengl/gl_transform.html 如果我理解这个管道(可以这么说)是正确的,如果在我的代码中,我会有这样的东西 这些坐标位于所谓的对象空间坐标中,我可以将每个值指定为范围内的值。
我刚刚学习了透视投影,并且发现在openGl中应用它有点令人困惑。 考虑一个简单的正方形。<br>在使用透视投影之前,我可以定义其顶点在[-1,1]空间中的坐标,对于{0.0f,0.0f,0.0 f,1.0f、1.0f、1.0 f、1,0.0 F}的输入,该正方形将占据窗口的第一象限 考虑我的代码中的以下部分: 设置矩阵: 制服: 顶点着色器: 但是,结果是一个空白屏幕 我需要在此应用哪些额外的转
我正在开发一个聊天应用程序。我有一个聊天活动,两个用户可以发送WhatsApp之类的消息,但我有个问题。 就像你在图中看到的(https://ibb.co/3cyYX01),滚动时视图乱糟糟的,我想我知道为什么了。 在查看了这些帖子后:RecyclerView在滚动时出错,Android:RecyclerView在滚动后内容出错 我假设问题可能出在函数中的回收器视图适配器中,因为我在某些视图(VI
需要得到文本 有一条红线在
支持 Grafana 视图展现 相较于 Open-Falcon 内建的 Dashboard,Grafana 可以很有弹性的自定义图表,并且可以针对 Dashboard 做权限控管、上标签以及查询,图表的展示选项也更多样化。本篇教学帮助您 做好 Open-Falcon 的面子工程! 安装和使用步骤 请参考 grafana open-falcon 致谢 感谢fastweb @kordan @masat