Android RecyclerView не отображает пользовательский вид; onDraw не вызывается - PullRequest
0 голосов
/ 10 июля 2020

Я перепробовал все, что угодно, и просмотрел множество вопросов на этом сайте. Ничего из этого не работает. Я следовал этому руководству: https://developer.android.com/guide/topics/ui/custom-components, и он не работает с RecyclerViews.

RecyclerView добавляет настраиваемый вид, и его размер ненулевой, подтвержденный через инспектор макета, но это прозрачный. Я пробовал решения setWillNotDraw () и invalidate (). Ничего. onDraw () не вызывается.

Вот настраиваемый вид:

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;
    }


}

Вот действие, содержащее RecylcerView

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);

    }
}

Вот адаптер:

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();
    }

}

Вот 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"
    />

Вот макет главной страницы:

<?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>

Почему не вызов RecyclerView onDraw для настраиваемого представления, созданного на основе указаний в Руководстве разработчика? Когда я использовал простой TextView в учебнике для RecylerView, он работал нормально и рисовал TextView, так почему бы ему не рисовать настраиваемый вид? Я буквально скопировал код из руководства RecyclerView и заменил TextView своим пользовательским View. Что-то мне не хватает в руководствах? Они несовместимы?

1 Ответ

0 голосов
/ 01 августа 2020

Проблема в том, что RecyclerViews имеют ширину 0dp. Использование wrap_content или match_parent устраняет проблему.

...