Android 在Recyclerview中使用画布绘制的自定义视图不工作

Android 在Recyclerview中使用画布绘制的自定义视图不工作,android,android-recyclerview,android-view,android-canvas,android-custom-view,Android,Android Recyclerview,Android View,Android Canvas,Android Custom View,我试图在recyclerview中从一个视图到另一个视图(画布绘制)绘制一条弧。所以我在recyclerview布局中添加了一个自定义视图。但是画得不好。它随机抽取recyclerview中的某些项目。这是我的密码: ArcView public class ArcView extends View { final RectF oval = new RectF(); Path myPath = new Path(); Paint paint; float lef

我试图在recyclerview中从一个视图到另一个视图(画布绘制)绘制一条弧。所以我在recyclerview布局中添加了一个自定义视图。但是画得不好。它随机抽取recyclerview中的某些项目。这是我的密码:

ArcView

public class ArcView extends View {

    final RectF oval = new RectF();
    Path myPath = new Path();
    Paint paint;
    float left, top, right, bottom;

    /**/
    private float mCanvasCenterX;

    private float mCenterCircleWidth, mCenterCircleHeight;

    /**/
    public ArcView(Context context) {
        super(context);
    }
    public ArcView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }
    public ArcView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    private void init(AttributeSet set) {
        if (set == null)
            return;
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        /*TypedArray typedArray = getContext().obtainStyledAttributes(set, R.styleable.FlightStatusArcView);
        typedArray.recycle();*/
    }

    public void setArcProperties(float l, float t, float r, float b) {
        left = l;
        top = t;
        right = r;
        bottom = b;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        oval.set(left, top, right, bottom);
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(5f);

        canvas.drawArc(oval, 180f, 180f, false, paint);
        drawArc(canvas);




    }



    private void drawArc(Canvas canvas) {

        canvas.save();

        Paint p = new Paint();
        p.setColor(Color.WHITE);
        p.setStyle(Paint.Style.FILL);
        p.setStrokeWidth(4f);

        float startX = oval.left + 20;
        float startY = oval.top + (oval.centerY() - oval.top)/ 2;

        Path path = new Path();
        path.moveTo(startX, startY);
        path.lineTo(startX + 20, startY + 20);
        path.lineTo(startX + 20, startY);
        path.lineTo(startX + 20, startY);
        path.close();

        canvas.drawPath(path, p);

        canvas.restore();
    }


}
活动\u main,保存回收视图的主要活动的布局

<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

    <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>


    <androidx.recyclerview.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/recycler_view"
            android:paddingEnd="5dp"
            android:paddingStart="5dp"
            android:scrollbars="vertical">

    </androidx.recyclerview.widget.RecyclerView>

</androidx.constraintlayout.widget.ConstraintLayout>

MyAdapter,recyclerview的适配器类。在这里,我试图画画布,但它什么也画不出来

class MyAdapter(var items: ArrayList<Item>) :
    RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
    fun updateItems(newItems: List<Item>) {
        items.clear()
        items.addAll(newItems)
        notifyDataSetChanged()
    }
    override fun onCreateViewHolder(parent: ViewGroup, p1: Int) = MyViewHolder(
        LayoutInflater.from(parent.context).inflate(R.layout.activity_arc_view, parent, false)
    )
    override fun getItemCount() = items.size
    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        holder.bind(items[position])
        val handler = Handler()
        handler.postDelayed(Runnable {
            setPropertiesAndDrawArc(holder)
        }, 1500)
    }
    class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val from = view.from_airport
        val to = view.to_airport
        val customView = view.customView
        val circleStart = view.circle_start
        val circleEnd = view.circle_end
        val inFlight = view.in_flight
        val flyingTime = view.flying_time
        fun bind(item: Item) {
            from.text = item.from
            to.text = item.to
        }
    }
    private fun setPropertiesAndDrawArc(holder: MyViewHolder) {
        val circleStartLocation = IntArray(2)
        holder.circleStart.getLocationOnScreen(circleStartLocation)
        val circleEndLocation = IntArray(2)
        holder.circleEnd.getLocationOnScreen(circleEndLocation)
        val inFlightLocation = IntArray(2)
        holder.inFlight.getLocationOnScreen(inFlightLocation)
        val fromAirportLocation = IntArray(2)
        holder.from.getLocationOnScreen(fromAirportLocation)
        val flyingTimeLocation = IntArray(2)
        holder.flyingTime.getLocationOnScreen(flyingTimeLocation)
        val toAirportLocation = IntArray(2)
        holder.to.getLocationOnScreen(toAirportLocation)
        holder.flyingTime.measure(0, 0)
        val flyingTimeHeight = holder.flyingTime.getMeasuredHeight()
        val flyingTimeTop = flyingTimeLocation[1] - flyingTimeHeight
        val left = circleStartLocation[0] + holder.circleStart.getWidth() / 2
        val top = inFlightLocation[1] + (flyingTimeTop - inFlightLocation[1]) / 2
        val right = circleEndLocation[0] + holder.circleEnd.getWidth() / 2
        val bottom = circleStartLocation[1] + (circleStartLocation[1] - inFlightLocation[1]) / 2
        holder.customView.setArcProperties(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat())
        holder.customView.invalidate()
    }
}
类MyAdapter(变量项:ArrayList):
RecyclerView.Adapter(){
乐趣更新项目(新项目:列表){
项目.清除()
items.addAll(newItems)
notifyDataSetChanged()
}
override onCreateViewHolder(父:ViewGroup,p1:Int)=MyViewHolder(
LayoutFlater.from(parent.context)。充气(R.layout.activity\u arc\u视图,parent,false)
)
重写getItemCount()=items.size
覆盖onBindViewHolder(holder:MyViewHolder,位置:Int){
持有者绑定(项目[位置])
val handler=handler()
handler.postDelayed(可运行{
设置属性和绘图弧(支架)
}, 1500)
}
类MyViewHolder(视图:视图):RecyclerView.ViewHolder(视图){
val from=从机场查看
val to=view.to_机场
val customView=view.customView
val circleStart=view.circle\u start
val circleEnd=视图。圆\u结束
val inFlight=飞行中的视图
val flyingTime=查看飞行时间
趣味绑定(物品:物品){
from.text=item.from
to.text=item.to
}
}
私人娱乐设置属性和绘图弧(持有人:MyViewHolder){
val circleStartLocation=阵列(2)
holder.circleStart.GetLocation屏幕(circleStart位置)
val circleEndLocation=IntArray(2)
holder.circleEnd.GetLocation屏幕(circleEndLocation)
val inFlightLocation=IntArray(2)
支架.飞行中.获取屏幕上的位置(飞行中位置)
val fromAirportLocation=IntArray(2)
holder.from.GetLocation屏幕(fromAirportLocation)
val flyingTimeLocation=IntArray(2)
holder.flyingTime.GetLocation屏幕(flyingTimeLocation)
val toAirportLocation=阵列(2)
holder.to.GetLocation屏幕(toAirportLocation)
holder.flyingTime.measure(0,0)
val flyingTimeHeight=holder.flyingTime.getMeasuredHeight()
val flyingTimeTop=flyingTimeLocation[1]-flyingTimeHeight
val left=circleStartLocation[0]+holder.circleStart.getWidth()/2
val top=inFlightLocation[1]+(flyingTimeTop-inFlightLocation[1])/2
val right=circleEndLocation[0]+holder.circleEnd.getWidth()/2
val bottom=circleStartLocation[1]+(circleStartLocation[1]-inFlightLocation[1])/2
holder.customView.setArcProperties(left.toFloat()、top.toFloat()、right.toFloat()、bottom.toFloat())
holder.customView.invalidate()
}
}
活动视图,回收视图项目行布局

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.example.customviewinrv.ArcView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/customView"
        android:elevation="2dp"
        android:layout_marginTop="0dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>


    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="170dp"
        android:background="@color/colorPrimaryDark"
        android:visibility="visible"
        android:layout_marginTop="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <View
            android:id="@+id/circle_start"
            android:layout_width="12dp"
            android:layout_height="12dp"
            android:background="@drawable/circle_white"
            app:layout_constraintBottom_toTopOf="@id/from_airport"
            app:layout_constraintEnd_toEndOf="@id/from_airport"
            app:layout_constraintStart_toStartOf="@id/from_airport" />

        <View
            android:id="@+id/circle_end"
            android:layout_width="12dp"
            android:layout_height="12dp"
            android:background="@drawable/circle_white"
            app:layout_constraintBottom_toTopOf="@id/to_airport"
            app:layout_constraintEnd_toEndOf="@id/to_airport"
            app:layout_constraintStart_toStartOf="@id/to_airport" />


        <TextView
            android:id="@+id/from_airport"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:gravity="center"
            android:text="Trivandrum\nInternational Airport"
            android:textColor="#FFFFFF"
            android:textSize="19sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent" />

        <TextView
            android:id="@+id/to_airport"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:gravity="center"
            android:text="Mineralnye Vody \nAirport"
            android:textColor="#FFFFFF"
            android:textSize="19sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintRight_toRightOf="parent" />

        <TextView
            android:id="@+id/in_flight"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:gravity="center"
            android:text="In-flight"
            android:textColor="#FFFFFF"
            android:textSize="19sp"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/flying_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp"
            android:gravity="center"
            android:text="Flying Time\n03h 30m"
            android:textColor="#FFFFFF"
            android:textSize="11sp"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@id/in_flight" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>


如果它是在没有recyclerview的正常活动中运行,则效果良好。我想知道如何在recyclerview中实现它。请帮助。

我没有看到对onDraw函数的超级调用,请执行以下操作:

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
....
....
...
更新

为自定义视图指定高度和宽度,而不是包裹内容:

<com.example.customviewinrv.ArcView
    android:layout_width="....."
    android:layout_height="......"

我没有看到对onDraw函数的超级调用,请执行以下操作:

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
....
....
...
更新

为自定义视图指定高度和宽度,而不是包裹内容:

<com.example.customviewinrv.ArcView
    android:layout_width="....."
    android:layout_height="......"

我理解您试图做的事情,但是您的代码太复杂,无法理解,但是您的方法不正确。首先,您应该在视图中使用onSizeChanged()回调来理解大小的变化,以便正确绘制圆弧。按照此约束布局,根据定义的约束(从机场和到机场)调整视图大小。因此,视图的宽度和高度可以适当调整,以便在此回调中进行所需的计算,然后可以根据刚刚在onSizeChanged中计算的值进行绘制操作,因此甚至不需要调用invalidate,因为系统会自动调用视图进行重绘。另一种选择是使用自定义视图组,但对于您的情况,这是不必要的。

我了解您试图做什么,但您的代码太复杂,无法理解,但您的方法不正确。首先,您应该在视图中使用onSizeChanged()回调来理解大小的变化,以便正确绘制圆弧。按照此约束布局,根据定义的约束(从机场和到机场)调整视图大小。因此,视图的宽度和高度可以适当调整,以便在此回调中进行所需的计算,然后可以根据刚刚在onSizeChanged中计算的值进行绘制操作,因此甚至不需要调用invalidate,因为系统会自动调用视图进行重绘。另一种选择是使用自定义视图组,但对于您的情况,它是不必要的。

我添加了一个图像。这就是我想要达到的目标。我如何给出高度和宽度?宽度:匹配\u父项和高度:170dp仅在RecycleService中的第一个项目中显示。是否看到其他项目?其他项目在那里,但没有为RecycleService中的其他项目绘制自定义视图我已添加图像。这就是我想要达到的目标。如何给出高度和宽度?宽度:match_parent and height:170dp仅在RecyclereView中的第一个项目中显示。是否看到其他项目?其他项目在那里,但没有为RecyclereView中的其他项目绘制自定义视图,就像我有相同的问题一样,在RecyclereView中使用画布绘制的自定义视图无法正确显示。还没有