Custom View RecyclerView项目问题

时间:2019-02-18 02:19:33

标签: android android-layout android-recyclerview android-animation android-custom-view

我创建了一个自定义视图,该视图用作RecyclerView项的根视图。我正在尝试为RecyclerView的每个项目设置动画(由自定义视图处理),但是它仅适用于RecyclerView中的第一个项目。它拧紧了第二个项目,对其他项目则完全无效。所有项目均会正确设置其高度的动画,只是它们不在顶部绘制灰色的ColorDrawable。

这是我的自定义视图:

class GestureActionLayout(context: Context, attributeSet: AttributeSet): FrameLayout(context, attributeSet) {

private val initialMeasuredHeight: Int by lazy { measuredHeight }

// The actual content being displayed
private lateinit var gestureViewChild: View
// The overlay to provide gesture based actions
private var foregroundDrawable: ForegroundDrawable

private var foregroundDrawableHeightRatio = 1.0f

private var shouldForegroundBeDrawn = false

init {

    val typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.GestureActionLayout)
    foregroundDrawableHeightRatio = typedArray.getFloat(R.styleable.GestureActionLayout_item_expand_ratio, 1.0f)
    typedArray.recycle()

    val positiveColour = ResourcesCompat.getColor(resources, R.color.colorTeal, null)
    val negativeColour = ResourcesCompat.getColor(resources, R.color.colorRed, null)

    foregroundDrawable = ForegroundDrawable(ColorDrawable(positiveColour), ColorDrawable(Color.DKGRAY), positiveColour, negativeColour)
    foregroundDrawable.alpha = 0
    foregroundDrawable.bounds = Rect(left, top, right, bottom)
    foregroundDrawable.callback = this

}

override fun dispatchDraw(canvas: Canvas?) {
    super.dispatchDraw(canvas)

    if (shouldForegroundBeDrawn && canvas != null)
        Log.e("DRAW", "FOREGROUND DRAW CALLED: $canvas")
        foregroundDrawable.draw(canvas)
}

fun setGestureActions(gestureActions: GestureActions) {

}

/**
 * Represents the drawable drawn on top of the content in the layout that
 * provides gesture driven actions
 */
class ForegroundDrawable(foregroundColourDrawable: ColorDrawable,
                         grayFillerDrawable: ColorDrawable,
                         private val positiveColour: Int,
                         private val negativeColour: Int):
    LayerDrawable(arrayOf(foregroundColourDrawable, grayFillerDrawable)) {

    private lateinit var swipeTransitionAnimator: ObjectAnimator
    private lateinit var changeColourAnimator: ValueAnimator

    private var isPositive: Boolean = true

    private val foregroundColourDrawable: ColorDrawable
        get() = getDrawable(0) as ColorDrawable

    private val greyFillerDrawable: ColorDrawable
        get() = getDrawable(1) as ColorDrawable

    fun animateSwipeGesture(alpha: Int) {

        if (alpha == greyFillerDrawable.alpha)
            return

        if (swipeTransitionAnimator != null)
            swipeTransitionAnimator.cancel()


        swipeTransitionAnimator = ObjectAnimator.ofInt(
            greyFillerDrawable,
            "alpha",
            greyFillerDrawable.alpha,
            alpha
        )

        swipeTransitionAnimator.duration = 200
        swipeTransitionAnimator.interpolator = FastOutSlowInInterpolator()
        swipeTransitionAnimator.start()

    }

    fun animateColourChange(isPositive: Boolean) {

        if(isPositive == this.isPositive)
            return

        this.isPositive = isPositive

        if (changeColourAnimator != null)
            changeColourAnimator.cancel()

        changeColourAnimator = ValueAnimator.ofArgb(foregroundColourDrawable.color,
            if (isPositive) positiveColour else negativeColour)
        changeColourAnimator.addUpdateListener {
            foregroundColourDrawable.color = it.animatedValue as Int
        }

        changeColourAnimator.duration = 200
        changeColourAnimator.interpolator = FastOutSlowInInterpolator()
        changeColourAnimator.start()

    }

}

fun displayActions() {

    Log.e("VALUES", "Top: $top Bottom: $bottom Right: $right Left: $left")

    shouldForegroundBeDrawn = true
    invalidate()

    val viewHeightAnimator = ValueAnimator.ofFloat(initialMeasuredHeight.toFloat(), (initialMeasuredHeight * foregroundDrawableHeightRatio))
    viewHeightAnimator.addUpdateListener {

        val update = it.animatedValue as Float
        val layoutParams = this.layoutParams
        layoutParams.height = update.toInt()
        this.layoutParams = layoutParams
        foregroundDrawable.setBounds(left, top, right, bottom)

    }

    val actionsAlphaAnimator = ObjectAnimator.ofInt(
        foregroundDrawable,
        "alpha",
        0,
        255
    )

    val animatorSet = AnimatorSet()
    animatorSet.duration = 300
    animatorSet.interpolator = FastOutSlowInInterpolator()
    animatorSet.playTogether(viewHeightAnimator, actionsAlphaAnimator)
    animatorSet.start()

}

fun setSwipeTranslation(translationY: Float) {

    if (!shouldForegroundBeDrawn)
        return

    // If user swipes down
    if (translationY < 0) {

        foregroundDrawable.animateColourChange(false)

    } else {

        foregroundDrawable.animateColourChange(true)

    }

    val translationYabs = Math.abs(translationY)

    if (translationYabs > (height / 3)) {
        foregroundDrawable.animateSwipeGesture(0)
    } else {
        foregroundDrawable.animateSwipeGesture(255)
    }


}

fun hideActions() {

    val viewHeightAnimator = ValueAnimator.ofFloat((initialMeasuredHeight * foregroundDrawableHeightRatio), initialMeasuredHeight.toFloat())
    viewHeightAnimator.addUpdateListener {

        val update = it.animatedValue as Float
        val layoutParams = this.layoutParams
        layoutParams.height = update.toInt()
        this.layoutParams = layoutParams
        foregroundDrawable.setBounds(left, top, right, bottom)

    }

    val actionsAlphaAnimator = ObjectAnimator.ofInt(
        foregroundDrawable,
        "alpha",
        255,
        0
    )

    val animatorSet = AnimatorSet()
    animatorSet.duration = 300
    animatorSet.interpolator = FastOutSlowInInterpolator()
    animatorSet.playTogether(viewHeightAnimator, actionsAlphaAnimator)

    animatorSet.doOnEnd {
        // Completely remove foreground
        shouldForegroundBeDrawn = false
        invalidate()
    }

    animatorSet.start()

}

override fun invalidateDrawable(drawable: Drawable) {
    if (drawable == foregroundDrawable)
        invalidate()
    else
        super.invalidateDrawable(drawable)
}

}

这是我的适配器:

class SubmissionsAdapter(private val clickListener: SubmissionItemClickListener,
                     private val submissions: List<Submission>):
RecyclerView.Adapter<SubmissionsAdapter.SubmissionViewHolder>() {

init {
    setHasStableIds(true)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SubmissionViewHolder {

    val submissionLayout = LayoutInflater.from(parent.context).inflate(R.layout.list_submission_item, parent, false)
    return SubmissionViewHolder(submissionLayout, clickListener)

}

override fun onBindViewHolder(holder: SubmissionViewHolder, position: Int) {
    holder.submissionIndex = position
    holder.submissionTitle.text = submissions[position].title
    holder.submissionAuthor.text = submissions[position].author
    holder.submissionSubreddit.text = submissions[position].subReddit
}

override fun getItemCount(): Int {
    return submissions.size
}

open class SubmissionViewHolder(
    itemView: View,
    listener: SubmissionItemClickListener
): RecyclerView.ViewHolder(itemView) {

    /*
        Lazy evaluated views to avoid null reference exceptions
     */
    val submissionTitle: TextView by lazy { itemView.findViewById<TextView>(R.id.submission_title) }
    val submissionAuthor: TextView by lazy { itemView.findViewById<TextView>(R.id.submission_author) }
    val submissionSubreddit: TextView by lazy { itemView.findViewById<TextView>(R.id.submission_subreddit) }
    val gestureLayout: GestureActionLayout by lazy { itemView as GestureActionLayout }

    var submissionIndex: Int by Delegates.notNull()
    var isLongPressed = false

    init {
        itemView.setOnClickListener {
            listener.onItemClick(submissionIndex)
        }
        gestureLayout.setOnLongClickListener {
            isLongPressed = true
            gestureLayout.displayActions()
            true
        }
        gestureLayout.setOnTouchListener { view, motionEvent ->

            Log.d("GESTURE", "Gesture instance: $gestureLayout")

            if (isLongPressed) {

                if (motionEvent.action == MotionEvent.ACTION_UP || motionEvent.action == MotionEvent.ACTION_CANCEL) {

                    gestureLayout.hideActions()
                    isLongPressed = false

                } else {

                    view.onTouchEvent(motionEvent)

                }

            } else {

                view.onTouchEvent(motionEvent)

            }

            true
        }
    }


}

}

请原谅混乱的代码,我现在正在使用自定义视图。以下是发生的情况的记录,我希望所有项目都像RecyclerView中的第一个项目一样进行动画处理:

https://vimeo.com/317881282

0 个答案:

没有答案