Я перепробовал все, что угодно, и просмотрел множество вопросов на этом сайте. Ничего из этого не работает. Я следовал этому руководству: 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. Что-то мне не хватает в руководствах? Они несовместимы?