简体   繁体   English

Android RecyclerView 未绘制自定义视图; 不调用 onDraw

[英]Android RecyclerView not drawing custom View; onDraw is not called

I have tried all sorts of things and sifted through lots of questions on this site.我已经尝试了各种各样的事情,并在这个网站上筛选了很多问题。 None of it is working.它都不起作用。 I followed this tutorial:https://developer.android.com/guide/topics/ui/custom-components and it does not work with RecyclerViews.我遵循了本教程:https://developer.android.com/guide/topics/ui/custom-components ,它不适用于 RecyclerViews。

The RecyclerView adds the custom view and it has a non zero size confirmed via the layout inspector, but it is transparent. RecyclerView 添加了自定义视图,并且通过布局检查器确认了它的非零大小,但它是透明的。 I have tried the setWillNotDraw() and invalidate() solutions.我已经尝试了 setWillNotDraw() 和 invalidate() 解决方案。 Nothing.没有什么。 onDraw() is not called.不调用 onDraw()。

Here is the custom View:这是自定义视图:

public class FunctionView extends View {

    Paint color = new Paint(Paint.ANTI_ALIAS_FLAG);

    float height = 0;
    float width = 0;

    private int minY = 0;

    private int maxY = 1;

    private float[] dataF = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    public FunctionView(Context context) {
        super(context);
    }

    public FunctionView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        // Account for padding
        float xpad = (float)(getPaddingLeft() + getPaddingRight());
        float ypad = (float)(getPaddingTop() + getPaddingBottom());

        width = (float)w - xpad;
        height = (float)h - ypad;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        color.setColor(Color.GREEN);
        if(NativeMethods.isFloat()){
            double xScale = ((double)width)/((double)dataF.length);
            double yScale = ((double)height)/((double)(maxY-minY));
            for(int i = 0; i < dataF.length; i+=2){
                canvas.drawLine((float)(((double)i)*xScale), (float)(((double)dataF[i])*yScale),
                        (float)(((double)(i+1))*xScale), (float)(((double)dataF[(i+1)])*yScale),
                        color);
            }
        }
    }

    void setData(double miny, double maxy, float[] values){
        this.minY = minY;
        this.maxY = maxY;
        this.dataF = values;
    }


}

Here is the Activity containing the RecylcerView这是包含 RecyclerView 的 Activity

public class MainActivity extends AppCompatActivity {

    private RecyclerView ampRecyclerView;
    private RecyclerView.Adapter ampAdapter;
    private RecyclerView.LayoutManager ampLayoutManager;

    private RecyclerView freqRecyclerView;
    private RecyclerView.Adapter freqAdapter;
    private RecyclerView.LayoutManager freqLayoutManager;

    List<FunctionView> myDataset = new ArrayList<FunctionView>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setUpRecyclerView();
    }

    private void setUpRecyclerView() {
        ampRecyclerView = (RecyclerView) findViewById(R.id.AmpRecyclerView);
        freqRecyclerView = (RecyclerView) findViewById(R.id.FreqRecyclerView);

        // use a linear layout manager
        ampLayoutManager = new LinearLayoutManager(this);
        freqLayoutManager = new LinearLayoutManager(this);

        ampRecyclerView.setLayoutManager(ampLayoutManager);
        freqRecyclerView.setLayoutManager(freqLayoutManager);

        myDataset.add(new FunctionView(this));

        // specify an adapter (see also next example)
        ampAdapter = new MainActivityAdapter(myDataset);
        ampRecyclerView.setAdapter(ampAdapter);

        freqAdapter = new MainActivityAdapter(myDataset);
        freqRecyclerView.setAdapter(freqAdapter);

    }
}

Here is the adapter:这是适配器:

class MainActivityAdapter extends RecyclerView.Adapter<MainActivityAdapter.FunctionViewHolder> {

    private List<FunctionView> views = new ArrayList<FunctionView>();

    // Provide a reference to the views for each data item
    // Complex data items may need more than one view per item, and
    // you provide access to all the views for a data item in a view holder
    public static class FunctionViewHolder extends RecyclerView.ViewHolder {

        // each data item is just a string in this case
        public FunctionView functionView;

        public FunctionViewHolder(FunctionView v) {
            super(v);
            functionView = v;
        }
    }

    // Provide a suitable constructor (depends on the kind of dataset)
    public MainActivityAdapter(List<FunctionView> myDataset) {
        views = myDataset;
    }

    // Create new views (invoked by the layout manager)
    @Override
    public MainActivityAdapter.FunctionViewHolder onCreateViewHolder(ViewGroup parent,
                                                             int viewType) {
        // create a new view
        FunctionView v = (FunctionView) LayoutInflater.from(parent.getContext())
                .inflate(R.layout.function_holder, parent, false);
        MainActivityAdapter.FunctionViewHolder vh = new MainActivityAdapter.FunctionViewHolder(v);
        return vh;
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(MainActivityAdapter.FunctionViewHolder holder, int position) {
        // - get element from your dataset at this position
        // - replace the contents of the view with that element
    //TODO set the data
        holder.functionView = views.get(position);
        holder.functionView.invalidate();
        holder.functionView.requestLayout();
    }

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return views.size();
    }

}

Here is the xml of the custom view:这是自定义视图的 xml:

<?xml version="1.0" encoding="utf-8"?>
<com.example.hellooboe.FunctionView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/function_view_holder"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />

Here is the layout for the main page:这是主页面的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_ll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
      android:id="@+id/AmpRecyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/FreqRecyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_weight="1" />
</LinearLayout>

Why won't a RecyclerView call onDraw for a custom View created from directions in the Developer's Guide?为什么 RecyclerView 不会为根据开发人员指南中的说明创建的自定义视图调用 onDraw? When I used a plain TextView in the tutorial for a RecylerView, it worked just fine and drew the TextView, so why won't it draw the custom view?当我在 RecylerView 的教程中使用普通的 TextView 时,它工作得很好并绘制了 TextView,那么为什么它不绘制自定义视图呢? I literally copied the code from the RecyclerView guide and replaced the TextView with my custom View.我从 RecyclerView 指南中复制了代码,并用我的自定义视图替换了 TextView。 Is there something I am missing from the guides?指南中有我遗漏的东西吗? Are they incompatible?它们不兼容吗?

The problem is that the RecyclerViews have a width of 0dp.问题是 RecyclerViews 的宽度为 0dp。 Using wrap_content or match_parent fixes the issue.使用 wrap_content 或 match_parent 解决了这个问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM