我创建了一个自定义视图,该视图用作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中的第一个项目一样进行动画处理: