Почему мой пользовательский вид элементов RecyclerView "невидим" - PullRequest
1 голос
/ 13 мая 2019

Мне нужно onDraw предметов RecyclerView.Используя подход, «обнаруженный» в этой SO-ссылке , я получил ... ну - частично там.

Обратите внимание, что в конечном итоге я хочу onDraw "поверх" пользовательского представления.Имеется в виду вызов super, чтобы позволить рисованию по умолчанию произойти, затем paint по неиспользуемым областям (вида) canvas.

Перед тем как начать движение по этому «настраиваемому виду, чтобы разрешить onDraw» дорогу,было то, что вы видите на слева ниже:

enter image description here enter image description here enter image description here

После этого у меня были все "невидимые" виды ( середина изображение выше).Я говорю «невидимка», потому что они все еще были там, чтобы их нажимали.Чтобы помочь мне визуализировать вещи (и немного onDraw подтверждение концепции), я переопределил onDraw в пользовательском представлении PuzzleView, просто вызвав canvas.drawRect, чтобы покрыть весь холст зеленым цветом, и теперь вижу право изображение выше.

Я не уверен, что я делаю здесь неправильно.

ТАКЖЕ: Если вам приходит в голову, что - ну, почему бы мне просто не onDraw все это ... это не практично по ряду причин.

Итак, вотмой PuzzleAdapter, как он есть :

class PuzzleAdapter(private val puzzles: List<Puzzle>) : RecyclerView.Adapter<PuzzleAdapter.PuzzleHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PuzzleAdapter.PuzzleHolder {
        //val v = LayoutInflater.from(parent.context).inflate(R.layout.item_puzzle, parent, false)
        //not inflating, creating PuzzleView (which is inflating itself)
        val v = PuzzleView(parent.context)
        v.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
        return PuzzleHolder(v)
    }

    override fun getItemCount() = puzzles.size

    //unchanged between these two versions
    override fun onBindViewHolder(h: PuzzleAdapter.PuzzleHolder, pos: Int) {
        val p = puzzles[pos]
        h.view.puzzleItem_text_ndx.text = "# " + p.descr()
        h.view.puzzleItem_text_details.text = "Ndx: ${p.puzzleNdx}"
        h.view.setOnClickListener {
            Log.d("##", "PuzzleHolder.onClick (bunch#${p.parentBunch.bunchID}; puzzle#${p.puzzleNdx})")
            val action = BunchFragmentDirections.navBunchToPuzzle(PuzzleParcel(p.parentBunch.bunchID, p.puzzleNdx))
            it.findNavController().navigate(action)
        }
    }

    inner class PuzzleHolder(v: View) : RecyclerView.ViewHolder(v) {
        val view: PuzzleView
        init {
            view = v as PuzzleView
        }
    }
}

PuzzleAdapter до :

class PuzzleAdapter(private val puzzles: List<Puzzle>) : RecyclerView.Adapter<PuzzleAdapter.PuzzleHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PuzzleAdapter.PuzzleHolder {
        val v = LayoutInflater.from(parent.context).inflate(R.layout.item_puzzle, parent, false)
        return PuzzleHolder(v)
    }

    override fun getItemCount() = puzzles.size

    //unchanged between these two versions
    override fun onBindViewHolder(h: PuzzleAdapter.PuzzleHolder, pos: Int) {
        val p = puzzles[pos]
        h.view.puzzleItem_text_ndx.text = "# " + p.descr()
        h.view.puzzleItem_text_details.text = "Ndx: ${p.puzzleNdx}"
        h.view.setOnClickListener {
            Log.d("##", "PuzzleHolder.onClick (bunch#${p.parentBunch.bunchID}; puzzle#${p.puzzleNdx})")
            val action = BunchFragmentDirections.navBunchToPuzzle(PuzzleParcel(p.parentBunch.bunchID, p.puzzleNdx))
            it.findNavController().navigate(action)
        }
    }

    inner class PuzzleHolder(v: View) : RecyclerView.ViewHolder(v) {
        var view: View = v
    }
}

PuzzleView ( пользовательский вид Я использую с адаптером):

class PuzzleView : RelativeLayout {
    constructor (context: Context) : super(context) { init(context, null, 0) }
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { init(context, attrs, 0) }
    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) { init(context, attrs, defStyle) }

    private fun init(context: Context, attrs: AttributeSet?, defStyle: Int) {
        inflate(getContext(), R.layout.item_puzzle, this)
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        //this.layout(l, t, r, b)
    }

    val rect = Rect(0, 0, 0, 0)
    val paint = Paint()
    override fun onDraw(canvas: Canvas) {
        //super.onDraw(canvas)
        Log.d("##", "PuzzleView.onDraw()")
        rect.right = width - 10
        rect.bottom = height - 10
        val bkgrColor = ContextCompat.getColor(App.context, R.color.Green)
        paint.style = Paint.Style.FILL
        paint.color = bkgrColor
        canvas.drawRect(rect, paint)
    }
}

Несколько соображений по поводу вышеуказанного класса / кода:

  • override fun onLayout требуется
  • У меня есть другие пользовательские представления, которые работают нормально (не в отношении RecyclerView) с пустым onLayout
  • Я пытался (это прокомментировано в приведенном выше коде) this.layout(l, t, r, b), но получаю стекисключение переполнения

Мои единственные настоящие мысли здесь: (1) что-то, что я должен делать в этом onLayout методе, но я не могу думать о чем;или (2) что-то не так с тем, как я надуваю item_puzzle, но - опять же - я не могу думать о чем.(Я попробовал несколько вещей на этом, но безрезультатно.) Я не могу думать ни о чем другом!

И вот весь другой код, который, я думаю, мог бы быть уместным:

из фрагмента , содержащего RecyclerView (это то, что показано на трех изображениях выше):

    bunch_recycler.layoutManager = GridLayoutManager(this.context, 3)
    bunch_recycler.adapter = PuzzleAdapter(bunch.puzzles)

наконец, XML для сам элемент, item_puzzle : enter image description here

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="16dp"
    android:layout_marginStart="16dp"
    android:layout_marginEnd="16dp"
    app:cardBackgroundColor="@color/facadeLight"
    app:cardElevation="0dp"
    >

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_puzzle"
        >

        <TextView
            android:id="@+id/puzzleItem_text_ndx"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginEnd="16dp"
            android:ellipsize="end"
            android:fontFamily="@font/showg"
            android:maxLines="1"
            android:text="17"
            android:textColor="@color/facadeDark"
            android:textSize="32sp"
            />

        <TextView
            android:id="@+id/puzzleItem_text_details"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/puzzleItem_text_ndx"
            android:layout_marginStart="8dp"
            android:text="details"
            android:textSize="12sp"
            />
    </RelativeLayout>

</androidx.cardview.widget.CardView>

ТАКЖЕ: если "пользовательское представление для разрешения onDraw" не является правильным(или лучший) способ достижения моей цели здесь, пожалуйста, дайте мне знать об этом.

Использование:

  • Windows 10
  • Android Studio 3.4
  • Kotlin 1.3.31
  • Gradle 3.4.0
  • и следующие:
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.1.0-alpha05'
    implementation 'androidx.core:core-ktx:1.2.0-alpha01'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.2.0-beta01'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0-beta01'

    implementation 'androidx.navigation:navigation-fragment-ktx:2.0.0'
    implementation 'androidx.navigation:navigation-ui-ktx:2.0.0'

Запоздалая мысль : Я видел (в 4 1/2-летнем видео youtube , переопределяющем getView, чтобы назначить подпредставления в похожей ситуации. Нет способа getView для переопределенияв сегодняшнем RecyclerView.Я вижу, что это getItemViewType(position: Int): Int, что тоже не кажется многообещающим (я немного читал об этом).Просто подумал, что упомяну об этом на случай, если это вызовет мысль для вас (где это не для меня)

Как всегда, спасибо за вашу помощь!

...