RelativeLayout无法强制转换为我的自定义列表视图

时间:2012-08-02 00:14:58

标签: java android android-layout android-widget

所以我正在编写一个自定义列表视图&适配器在列表视图中显示我自己的自定义项行。我有一个功能列表视图,其功能是在选择模式之间切换,并通过列表视图行xml文件中的自定义相对布局来检查列表行项目。现在我正在尝试添加拖放功能,以使用目标代码为android v3.0及更高版本来访问列表视图项。我在这个网站上遇到了这个post,用于拖放的优秀实现,现在我将它添加到我的项目中。 Github source here

当我编译我的项目时,我收到了一个强制转换异常错误,如我的帖子标题中所述,我遇到了麻烦。如果我的自定义相对布局实现可检查,或者拖放的自定义列表视图等,我无法解决。这是我的日志输出

08-02 09:53:37.065: W/dalvikvm(16119): threadid=1: thread exiting with uncaught exception (group=0x40c6f1f8)
08-02 09:53:37.090: E/AndroidRuntime(16119): FATAL EXCEPTION: main
08-02 09:53:37.090: E/AndroidRuntime(16119): java.lang.ClassCastException: android.widget.RelativeLayout cannot be cast to au.drp.mylistview.draganddrop.DragSortListView
08-02 09:53:37.090: E/AndroidRuntime(16119):    at au.drp.mylistview.MyListViewAdapter.getView(MyListViewAdapter.java:62)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at au.drp.mylistview.draganddrop.DragSortListView$AdapterWrapper.getView(DragSortListView.java:270)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.AbsListView.obtainView(AbsListView.java:2424)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.ListView.makeAndAddView(ListView.java:1781)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.ListView.fillDown(ListView.java:679)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.ListView.fillFromTop(ListView.java:739)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.ListView.layoutChildren(ListView.java:1632)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at au.drp.mylistview.draganddrop.DragSortListView.layoutChildren(DragSortListView.java:961)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.AbsListView.onLayout(AbsListView.java:2254)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.View.layout(View.java:11467)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.ViewGroup.layout(ViewGroup.java:4237)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.View.layout(View.java:11467)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.ViewGroup.layout(ViewGroup.java:4237)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1644)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1502)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.LinearLayout.onLayout(LinearLayout.java:1415)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.View.layout(View.java:11467)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.ViewGroup.layout(ViewGroup.java:4237)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.View.layout(View.java:11467)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.ViewGroup.layout(ViewGroup.java:4237)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1721)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2678)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.os.Handler.dispatchMessage(Handler.java:99)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.os.Looper.loop(Looper.java:137)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at android.app.ActivityThread.main(ActivityThread.java:4514)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at java.lang.reflect.Method.invokeNative(Native Method)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at java.lang.reflect.Method.invoke(Method.java:511)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:993)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:760)
08-02 09:53:37.090: E/AndroidRuntime(16119):    at dalvik.system.NativeStart.main(Native Method)

但是我发现通过更改DragSortListView类中的错误部分我可以更改结果,但仍然是相对布局类型和列表视图之间的强制转换异常错误。我谈到的这一部分是DragSortListView类的以下getView代码。我尝试更改的是RelativeLayout变量类型并转换为CheckableRelativelayout。

注意:我在代码“//不喜欢这个陈述代码”中的注释是错误行

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

  RelativeLayout v;
  View child;

  //Log.d("mobeta", "getView: position="+position+" convertView="+convertView);
  if (convertView != null) {

    v = (RelativeLayout) convertView;
    View oldChild = v.getChildAt(0);

    //child = super.getView(position, oldChild, v);
    child = mAdapter.getView(position, oldChild, v);
    if (child != oldChild) {
      // shouldn't get here if user is reusing convertViews properly
      v.removeViewAt(0);
      v.addView(child);
      // check that tags are equal too?
      v.setTag(child.findViewById(R.id.drag));
    }

  } else {
    AbsListView.LayoutParams params =
      new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    v = new RelativeLayout(getContext());
    v.setLayoutParams(params);
    child = mAdapter.getView(position, null, v);  //DOES NOT LIKE THIS STATEMENT CODE
    v.addView(child);

    v.setTag(child.findViewById(R.id.drag));
  }

这是我的适配器类的getView

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // This is how you would determine if this particular item is checked
    // when the view gets created
    // --       
    final DragSortListView lv = (DragSortListView) parent;  // DOES NOT LIKE THIS STATEMENT CODE
    final boolean isChecked = lv.isItemChecked(position);

    // Get the listview Choice Mode
    //
    final int selectionMode = lv.getChoiceMode();

    // The item we want to get the view for
    // --
    Item currentItem = getItem(position);

    // Re-use the view if possible (recycle)
    // --
    ViewHolder holder = null;
    //final View mView = mInflator.inflate(R.layout.listview_row, null);
    if (convertView == null) {
        convertView = mInflator.inflate(R.layout.listview_row, null);
        holder = new ViewHolder();
        holder.txtTitle = (TextView) convertView.findViewById(R.id.title);
        holder.txtDescription = (TextView) convertView.findViewById(R.id.description);
        holder.txtSessionCount = (TextView) convertView.findViewById(R.id.session_count);
        holder.listThumbnailImage = (ImageView) convertView.findViewById(R.id.list_image);
        holder.listStatusIndicatorImage = (ImageView) convertView.findViewById(R.id.drag);
        holder.Checkbox = (InertCheckBox) convertView.findViewById(R.id.inertCheckBox);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder)convertView.getTag();
    }
    // End recycler
    //

    holder.txtTitle.setText(currentItem.getTitle());
    holder.txtDescription.setText(currentItem.getDescription());
    holder.txtSessionCount.setText(currentItem.getSessionCount());
    holder.listThumbnailImage.setImageBitmap((Bitmap) currentItem.getThumbnailImage());

    // Now the Status ImageView and/or the InertCheckBox view
    switch (selectionMode) {
    case ListView.CHOICE_MODE_NONE:
        holder.Checkbox.setVisibility(InertCheckBox.INVISIBLE);
        holder.listStatusIndicatorImage.setVisibility(ImageView.VISIBLE);

        holder.listStatusIndicatorImage.setAdjustViewBounds(true);
        holder.listStatusIndicatorImage.setMaxHeight(48);
        holder.listStatusIndicatorImage.setMaxWidth(48);
        if (!dndMode) {
            holder.listStatusIndicatorImage.setImageBitmap((Bitmap) currentItem.getListIndicatorImage());

        } else {
            holder.listStatusIndicatorImage.setImageResource(R.drawable.list_icon_reorder_holo_dark);
        }   
        holder.listStatusIndicatorImage.setScaleType(ScaleType.CENTER_INSIDE);
        break;
    case ListView.CHOICE_MODE_SINGLE: case ListView.CHOICE_MODE_MULTIPLE:
        MyListViewAdapter.dndMode = false;
        holder.listStatusIndicatorImage.setVisibility(ImageView.INVISIBLE);
        holder.Checkbox.setVisibility(InertCheckBox.VISIBLE);
        if (!chkbxDelete) {
            holder.Checkbox.setButtonDrawable(R.drawable.checkbox);
        } else {
            holder.Checkbox.setButtonDrawable(R.drawable.checkboxdelete);
        }
        holder.Checkbox.setChecked(isChecked);
        break;
    }           

    return convertView;
}

我的列表视图行布局

<?xml version="1.0" encoding="utf-8"?>
<au.drp.mylistview.widget.CheckableRelativeLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:drp="http://schemas.android.com/apk/res/au.drp.mylistview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/list_selector"
android:orientation="horizontal"
android:padding="2dip" >

<!-- ListRow Left side Thumbnail image -->

<LinearLayout
    android:id="@+id/thumbnail"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:layout_marginRight="5dip"
    android:gravity="center_vertical"
    android:padding="3dip" >

    <ImageView
        android:id="@+id/list_image"
        android:layout_width="50dip"
        android:layout_height="50dip"
        android:src="@drawable/icon" >
    </ImageView>
</LinearLayout>

<!-- Title Of Exercise -->
<TextView
    android:id="@+id/title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignTop="@+id/thumbnail"
    android:layout_toLeftOf="@+id/inertCheckBox"
    android:layout_toRightOf="@+id/thumbnail"
    android:text="This is the Title - Testing 1 2 3 "
    android:textColor="#ffffffff"
    android:textSize="18dip"
    android:textStyle="bold"
    android:typeface="sans" />

<TextView
    android:id="@+id/description"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/title"
    android:layout_toLeftOf="@+id/inertCheckBox"
    android:layout_toRightOf="@id/thumbnail"
    android:text="this is the description - Testing 1 2 3"
    android:textColor="#ffcccccc"
    android:textSize="14dip" />

<TextView
    android:id="@+id/session_count"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:layout_alignParentTop="true"
    android:gravity="right"
    android:text="100"
    android:textColor="#ffcccccc"
    android:textSize="10dip"
    android:textStyle="bold" />
<ImageView
    android:id="@+id/drag"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBottom="@id/inertCheckBox"
    android:layout_alignLeft="@id/inertCheckBox"
    android:layout_alignParentRight="true"
    android:layout_alignTop="@id/inertCheckBox"
    android:layout_below="@id/session_count"
    android:layout_centerVertical="false"
    android:adjustViewBounds="true"
    android:maxHeight="32dip"
    android:maxWidth="32dip"
    android:scaleType="center"
    android:src="@drawable/arrow_32_holo_dark"
    android:visibility="visible" />
<au.drp.mylistview.widget.InertCheckBox
    android:id="@+id/inertCheckBox"
    style="@drawable/checkbox"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:layout_below="@id/session_count"
    android:button="@drawable/checkbox"
    android:checked="true"
    android:clickable="false"
    android:focusable="false"
    android:focusableInTouchMode="false" />

</au.drp.mylistview.widget.CheckableRelativeLayout>

我的CheckableRelativeLayout类

public class CheckableRelativeLayout extends RelativeLayout implements Checkable {

private boolean isChecked;
private List<Checkable> checkableViews;

public CheckableRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    initialise(attrs);
}

public CheckableRelativeLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    initialise(attrs);
}

public CheckableRelativeLayout(Context context, int checkableId) {
    super(context);
    initialise(null);
}

/*
 * @see android.widget.Checkable#isChecked()
 */
public boolean isChecked() {
    return isChecked;
}

/*
 * @see android.widget.Checkable#setChecked(boolean)
 */
public void setChecked(boolean isChecked) {
    this.isChecked = isChecked;
    for (Checkable c : checkableViews) {
        c.setChecked(isChecked);
    }
}

/*
 * @see android.widget.Checkable#toggle()
 */
public void toggle() {
    this.isChecked = !this.isChecked;
    for (Checkable c : checkableViews) {
        c.toggle();
    }
}

@Override
protected void onFinishInflate() {
    super.onFinishInflate();

    final int childCount = this.getChildCount();
    for (int i = 0; i < childCount; ++i) {
        findCheckableChildren(this.getChildAt(i));
    }
}

/**
 * Read the custom XML attributes
 */
private void initialise(AttributeSet attrs) {
    this.isChecked = false;
    this.checkableViews = new ArrayList<Checkable>(5);
}

/**
 * Add to our checkable list all the children of the view that implement the
 * interface Checkable
 */
private void findCheckableChildren(View v) {
    if (v instanceof Checkable) {
        this.checkableViews.add((Checkable) v);
    }

    if (v instanceof ViewGroup) {
        final ViewGroup vg = (ViewGroup) v;
        final int childCount = vg.getChildCount();
        for (int i = 0; i < childCount; ++i) {
            findCheckableChildren(vg.getChildAt(i));
        }
    }
}

}

DragsortListView的自定义列表视图布局

<?xml version="1.0" encoding="utf-8"?>
<au.drp.mylistview.draganddrop.DragSortListView
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:dslv="http://schemas.android.com/apk/res/au.drp.mylistview"
  android:id="@android:id/list"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:paddingTop="20dp"
  android:paddingBottom="20dp"
  dslv:collapsed_height="5dp"
  dslv:drag_scroll_start="0.33"
  dslv:max_drag_scroll_speed="0.5"
  dslv:float_background_color="#000000"
  dslv:remove_mode="none"
  dslv:track_drag_scroll="false" />

有人能够向我指出我的错误吗?我被卡住了。

感谢,

保罗。

3 个答案:

答案 0 :(得分:0)

好的,我发现了问题!但提出了另一个问题。问题是我的MyListViewAdapter类中的这一行

 final ListView lv = (ListView) parent;  // DOES NOT LIKE THIS STATEMENT CODE

如果我发表评论并且使用lv的所有内容运行并拖放工作!但现在的问题是如何确定列表视图中的项是否被选中?因此,如果检查了视图,这就是我获取的方式

    // This is how you would determine if this particular item is checked
    // when the view gets created
    // --       
    final ListView lv = (ListView) parent;  // DOES NOT LIKE THIS STATEMENT CODE
    final boolean isChecked = lv.isItemChecked(position);

    // Get the listview Choice Mode
    //
    final int selectionMode = lv.getChoiceMode();

我想我可以在代码中添加一个if语句,用于何时使用拖放支持模式,但这似乎是一种解决方法。有什么想法吗?

答案 1 :(得分:0)

传递到View parent

getView参数不是包含列表的ListView,它只是convertView的父级(即,用于充气)。从根本上说,这不是ListView对象,这就是为什么在尝试投射时获得ClassCastException的原因,因为它无法转换为ListView。您应该将ListView对象传递到Adapter sublcass的构造函数,然后在getView中使用它。

答案 2 :(得分:0)

在我的情况下,ClassCastException是因为在my_custom_view.xml(我用来给MyCustomView充气)中我定义了它的id

android:id="@+id/myCustomView"

然后在my_activity.xml中再次定义其id

<com.example.app.views.custom.MyCustomView
        android:id="@+id/myCustomView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

id删除my_custom_view.xml参数解决了该问题。