自定义视图向下转换不起作用
Custom view downcasting not working
我有一个自定义视图 CourseRaceButton,它扩展了 LinearLayout 并将显示在 RecyclerView 中。使用自定义视图的目的是将状态控件枚举分别嵌入到每个按钮中,以便可以根据选择的种族或路线更改颜色等。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/courseRace_width"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_margin="@dimen/courseRace_margin"
android:background="@drawable/courses_border"
android:padding="@dimen/courseRace_padding"
>
<TextView
android:id="@+id/course_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="2">
<TextView
android:id="@+id/course_name"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="@dimen/default_padding"
android:text="Ascot"
android:textColor="@color/brb_blue">
</TextView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:weightSum="2">
<TextView
android:id="@+id/course_time"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="@dimen/default_padding"
android:text="11:00"
android:textColor="@color/brb_blue"/>
<TextView
android:id="@+id/course_MTP"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="right"
android:padding="@dimen/default_padding"
android:text="MTP 10"
android:textColor="@color/brb_blue"/>
</LinearLayout>
</LinearLayout>
这是视图的 XML。我将包含的 viewGroup 保留为 LinearLayout(而不是我的 CourseRaceButton,因为它导致 inflation 问题,并且因为我不需要在以前的自定义 LinearLayout 中这样做)。
public class CourseRaceButton extends LinearLayout{
private ButtonStates state;
private TextView title;
private TextView time;
private TextView mtp;
public CourseRaceButton(Context context) {
super(context);
init();
}
public CourseRaceButton(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public CourseRaceButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void init(){
LayoutInflater.from(getContext()).inflate(
R.layout.course_layout, this);
title = findViewById(R.id.course_id);
time = findViewById(R.id.course_time);
mtp = findViewById(R.id.course_MTP);
state = ButtonStates.UNSELECTED;
}
这是我的 RecyclerView 适配器的 onBindViewHolder:
@Override
public void onBindViewHolder(final holder holder, final int position) {
holder.button.getTitle().setText(courses.get(position).name);
if (!initialised) {
holder.button.setState(ButtonStates.UNSELECTED);
previousSelectedCourse = holder.itemView;
currentCourse=courses.get(position);
if (position == 0) {
OnCourseClickListener.onCourseClick(currentCourse);
holder.button.setState(ButtonStates.SELECTED);
previousSelectedCourse = holder.itemView;
}
initialised = true;
}
最好将 previousSelectedCourse = holder.itemView 向下转换为我的 CourseRaceButton(稍后详细介绍)
这是 OnClick:
@Override
public void onClick(View v) {
Log.e("TESTING ******"," ON TOUCH " );
/** Sort out colours as we may have changed button */
currentCourse = courses.get(this.getAdapterPosition());
CourseRaceButton b = (CourseRaceButton) v;
if(b.getState() == ButtonStates.SELECTED){
return;
现在如果点击一个按钮,我会在这一行得到一个错误
CourseRaceButton b = (CourseRaceButton) v;
java.lang.ClassCastException: android.widget.LinearLayout 无法转换为 com.ineda.terminal.CourseRaceButton
我的 CourseRaceButton 扩展了 LinearLayout,因此 CourseRaceButton 是一个 LinearLayout,那么为什么我不能将视图向下转换为 CourseRaceButton?我假设 v 是一个 LinearLayout,因为它在 XML 中是这样声明的,但是将它更改为 CourseRaceButton 会给我一个错误的无限循环(因为显然充气器正在尝试创建引用自身的布局).
如果我不能向下转换 LinearLayout,我就不能更改它的状态 Enum 来更新它的颜色。
可能有几种解决方法,我愿意接受其中的任何一种
编辑:
这是 onCreateViewHolder
public holder onCreateViewHolder(ViewGroup parent, int viewType) {
View iv = LayoutInflater.from(parent.getContext()).inflate(R.layout.course_layout, parent, false);
return new holder(iv);
}
根据要求,这是我将 course_layout.xml 中的第一个 LinearLayout 更改为我的 CourseRaceButton 时得到的无限循环的 1 个循环。
at com.ineda.terminal.CourseRaceButton.init(CourseRaceButton.java:41)
at com.ineda.terminal.CourseRaceButton.<init>(CourseRaceButton.java:31)
at java.lang.reflect.Constructor.newInstance0!(Native method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:430)
at android.view.LayoutInflater.createView(LayoutInflater.java:645)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:787)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727)
at android.view.LayoutInflater.inflate(LayoutInflater.java:495)
- locked <0x05c7192a> (a java.lang.Object[])
at android.view.LayoutInflater.inflate(LayoutInflater.java:426)
at android.view.LayoutInflater.inflate(LayoutInflater.java:377)
at com.ineda.terminal.CourseRaceButton.init(CourseRaceButton.java:41)
at com.ineda.terminal.CourseRaceButton.<init>(CourseRaceButton.java:31)
at java.lang.reflect.Constructor.newInstance0!(Native method)
10-19 15:00:41.792 17508-17508/ineda.com.genericterminal.ineda A/art:
art/runtime/runtime.cc:422] at
java.lang.reflect.Constructor.newInstance(Constructor.java:430)
at android.view.LayoutInflater.createView(LayoutInflater.java:645)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:787)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727)
at android.view.LayoutInflater.inflate(LayoutInflater.java:495)
- locked <0x05c7192a> (a java.lang.Object[])
at android.view.LayoutInflater.inflate(LayoutInflater.java:426)
at android.view.LayoutInflater.inflate(LayoutInflater.java:377)
创建 ViewHolder 时,您可以通过这样做从 XML 膨胀它:
public holder onCreateViewHolder(ViewGroup parent, int viewType) {
View iv =
LayoutInflater.from(parent.getContext()).inflate(R.layout.course_layout,
parent, false);
return new holder(iv);
}
显然,Adapter 对您的自定义视图一无所知,因为 ViewHolder 是使用常规 LinearLayout 作为根创建的。
因此,根据您的需要,您需要通过手动实例化将自定义视图的实例传递给 ViewHolder:
public holder onCreateViewHolder(ViewGroup parent, int viewType) {
return new holder(new CourseRaceButton(context));
}
或者您需要使用自定义视图作为 XML 的根。但是随后您将需要修复您的逻辑中的一个缺陷 - 不要通过声明自定义视图的相同布局来扩充您的自定义视图。这就是为什么你会得到这个无限循环的异常。
我有一个自定义视图 CourseRaceButton,它扩展了 LinearLayout 并将显示在 RecyclerView 中。使用自定义视图的目的是将状态控件枚举分别嵌入到每个按钮中,以便可以根据选择的种族或路线更改颜色等。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/courseRace_width"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_margin="@dimen/courseRace_margin"
android:background="@drawable/courses_border"
android:padding="@dimen/courseRace_padding"
>
<TextView
android:id="@+id/course_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="2">
<TextView
android:id="@+id/course_name"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="@dimen/default_padding"
android:text="Ascot"
android:textColor="@color/brb_blue">
</TextView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:weightSum="2">
<TextView
android:id="@+id/course_time"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="@dimen/default_padding"
android:text="11:00"
android:textColor="@color/brb_blue"/>
<TextView
android:id="@+id/course_MTP"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="right"
android:padding="@dimen/default_padding"
android:text="MTP 10"
android:textColor="@color/brb_blue"/>
</LinearLayout>
</LinearLayout>
这是视图的 XML。我将包含的 viewGroup 保留为 LinearLayout(而不是我的 CourseRaceButton,因为它导致 inflation 问题,并且因为我不需要在以前的自定义 LinearLayout 中这样做)。
public class CourseRaceButton extends LinearLayout{
private ButtonStates state;
private TextView title;
private TextView time;
private TextView mtp;
public CourseRaceButton(Context context) {
super(context);
init();
}
public CourseRaceButton(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public CourseRaceButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void init(){
LayoutInflater.from(getContext()).inflate(
R.layout.course_layout, this);
title = findViewById(R.id.course_id);
time = findViewById(R.id.course_time);
mtp = findViewById(R.id.course_MTP);
state = ButtonStates.UNSELECTED;
}
这是我的 RecyclerView 适配器的 onBindViewHolder:
@Override
public void onBindViewHolder(final holder holder, final int position) {
holder.button.getTitle().setText(courses.get(position).name);
if (!initialised) {
holder.button.setState(ButtonStates.UNSELECTED);
previousSelectedCourse = holder.itemView;
currentCourse=courses.get(position);
if (position == 0) {
OnCourseClickListener.onCourseClick(currentCourse);
holder.button.setState(ButtonStates.SELECTED);
previousSelectedCourse = holder.itemView;
}
initialised = true;
}
最好将 previousSelectedCourse = holder.itemView 向下转换为我的 CourseRaceButton(稍后详细介绍)
这是 OnClick:
@Override
public void onClick(View v) {
Log.e("TESTING ******"," ON TOUCH " );
/** Sort out colours as we may have changed button */
currentCourse = courses.get(this.getAdapterPosition());
CourseRaceButton b = (CourseRaceButton) v;
if(b.getState() == ButtonStates.SELECTED){
return;
现在如果点击一个按钮,我会在这一行得到一个错误
CourseRaceButton b = (CourseRaceButton) v;
java.lang.ClassCastException: android.widget.LinearLayout 无法转换为 com.ineda.terminal.CourseRaceButton
我的 CourseRaceButton 扩展了 LinearLayout,因此 CourseRaceButton 是一个 LinearLayout,那么为什么我不能将视图向下转换为 CourseRaceButton?我假设 v 是一个 LinearLayout,因为它在 XML 中是这样声明的,但是将它更改为 CourseRaceButton 会给我一个错误的无限循环(因为显然充气器正在尝试创建引用自身的布局).
如果我不能向下转换 LinearLayout,我就不能更改它的状态 Enum 来更新它的颜色。
可能有几种解决方法,我愿意接受其中的任何一种
编辑: 这是 onCreateViewHolder
public holder onCreateViewHolder(ViewGroup parent, int viewType) {
View iv = LayoutInflater.from(parent.getContext()).inflate(R.layout.course_layout, parent, false);
return new holder(iv);
}
根据要求,这是我将 course_layout.xml 中的第一个 LinearLayout 更改为我的 CourseRaceButton 时得到的无限循环的 1 个循环。
at com.ineda.terminal.CourseRaceButton.init(CourseRaceButton.java:41)
at com.ineda.terminal.CourseRaceButton.<init>(CourseRaceButton.java:31)
at java.lang.reflect.Constructor.newInstance0!(Native method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:430)
at android.view.LayoutInflater.createView(LayoutInflater.java:645)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:787)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727)
at android.view.LayoutInflater.inflate(LayoutInflater.java:495)
- locked <0x05c7192a> (a java.lang.Object[])
at android.view.LayoutInflater.inflate(LayoutInflater.java:426)
at android.view.LayoutInflater.inflate(LayoutInflater.java:377)
at com.ineda.terminal.CourseRaceButton.init(CourseRaceButton.java:41)
at com.ineda.terminal.CourseRaceButton.<init>(CourseRaceButton.java:31)
at java.lang.reflect.Constructor.newInstance0!(Native method)
10-19 15:00:41.792 17508-17508/ineda.com.genericterminal.ineda A/art:
art/runtime/runtime.cc:422] at
java.lang.reflect.Constructor.newInstance(Constructor.java:430)
at android.view.LayoutInflater.createView(LayoutInflater.java:645)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:787)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727)
at android.view.LayoutInflater.inflate(LayoutInflater.java:495)
- locked <0x05c7192a> (a java.lang.Object[])
at android.view.LayoutInflater.inflate(LayoutInflater.java:426)
at android.view.LayoutInflater.inflate(LayoutInflater.java:377)
创建 ViewHolder 时,您可以通过这样做从 XML 膨胀它:
public holder onCreateViewHolder(ViewGroup parent, int viewType) {
View iv =
LayoutInflater.from(parent.getContext()).inflate(R.layout.course_layout,
parent, false);
return new holder(iv);
}
显然,Adapter 对您的自定义视图一无所知,因为 ViewHolder 是使用常规 LinearLayout 作为根创建的。
因此,根据您的需要,您需要通过手动实例化将自定义视图的实例传递给 ViewHolder:
public holder onCreateViewHolder(ViewGroup parent, int viewType) {
return new holder(new CourseRaceButton(context));
}
或者您需要使用自定义视图作为 XML 的根。但是随后您将需要修复您的逻辑中的一个缺陷 - 不要通过声明自定义视图的相同布局来扩充您的自定义视图。这就是为什么你会得到这个无限循环的异常。