【问题标题】:Android : Animate Rating Bar to expand and shrink each starAndroid:动画评分栏以扩大和缩小每颗星
【发布时间】:2020-11-06 06:07:28
【问题描述】:

我有一个评级栏,它显示 5 颗星,我想通过归档从 0 到 5 进行动画处理,具体取决于传递到视图中的评级值,并且每颗星的大小都会扩大,然后收缩回其原始大小每颗已着色/填充的星星。

例如,5 颗星中的所有 4 颗星都应该以 3.5 星评级为例进行扩展和缩小。

我已经用下面的代码将它从 0 填充到 3.5,但不知道如何扩展每个应用了填充的星?

这可能吗?

这是我目前所拥有的:

ObjectAnimator.ofFloat(starRating, "rating", 0f, 3.5f).apply {
    duration = animDuration
    addListener(onEachStarFilled?/onEachFrame?? = {
        //todo expand each star? how?
    })
    start()
}

【问题讨论】:

  • 为此,您必须放置五个图像视图,然后根据需要为每个图像视图设置动画!
  • 我猜默认的android评分栏不会这样做?我试图避免重新创建评分栏,因为我会遇到另一个问题,即根据传递的进度值部分填写每颗星。
  • Android 默认评级星不这样做,我建议只使用简单的水平线性布局和五个图像视图。
  • 我还需要它像一个进度条来相应地填充每个进度条。例如,如果您的评分为 3.25。第 4 颗星只能填充 25%

标签: android kotlin animation


【解决方案1】:

添加一个容器来保存五个带有默认图像的图像视图。

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:id="@+id/start_ratting"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent">
    <ImageView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@android:color/transparent"
        android:scaleType="fitCenter"
        android:src="@drawable/empty"
        android:id="@+id/star_1"/>
    <ImageView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@android:color/transparent"
        android:src="@drawable/empty"
        android:scaleType="fitCenter"
        android:id="@+id/star_2"/>
    <ImageView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@android:color/transparent"
        android:scaleType="fitCenter"
        android:src="@drawable/empty"
        android:id="@+id/star_3"/>
    <ImageView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@android:color/transparent"
        android:scaleType="fitCenter"
        android:src="@drawable/empty"
        android:id="@+id/star_4"/>
    <ImageView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:src="@drawable/empty"
        android:background="@android:color/transparent"
        android:scaleType="fitCenter"
        android:id="@+id/star_5"/>
</LinearLayout>

然后添加动画师

private fun expandHorizontal(v: ImageView, image: Drawable) {
    val width: Int = v.width
    v.visibility = View.VISIBLE
    v.layoutParams.width = 0
    v.setImageDrawable(image)
    val valueAnimator = ValueAnimator.ofInt(0, width)
    valueAnimator.addUpdateListener { animation ->
        v.layoutParams.width = animation.animatedValue as Int
        v.requestLayout()
    }
    valueAnimator.interpolator = DecelerateInterpolator()
    valueAnimator.duration = VIEW_TRANSITION_TIME
    valueAnimator.start()
}

在需要时调用设置星值

 private fun setStarValue(ratting: Double){
    star1.visibility = View.INVISIBLE
    star2.visibility = View.INVISIBLE
    star3.visibility = View.INVISIBLE
    star4.visibility = View.INVISIBLE
    star5.visibility = View.INVISIBLE
    var i = 0
    for(i in 0..5){
        when(i){
            0->{
                val res = ratting - i;
                if(res >= 1){
                    Log.d(TAG, "start 1")
                    getDrawable(R.drawable.full)?.let { expandHorizontal(star1, it) }
                }
                else if(res > 0 && res < 1){
                    Log.d(TAG, "start half")
                    getDrawable(R.drawable.half)?.let { expandHorizontal(star1, it) }
                }
                else{
                    Log.d(TAG, "no start")
                    getDrawable(R.drawable.empty)?.let { expandHorizontal(star1, it) }
                }
            }
            1 -> {
                val res = ratting - i;
                if(res >= 1){
                    Log.d(TAG, "start 2")
                    getDrawable(R.drawable.full)?.let { expandHorizontal(star2, it) }
                }
                else if(res > 0 && res < 1){
                    Log.d(TAG, "start two and half")
                    getDrawable(R.drawable.half)?.let { expandHorizontal(star2, it) }
                }
                else{
                    Log.d(TAG, "no start")
                    getDrawable(R.drawable.empty)?.let { expandHorizontal(star2, it) }
                }
            }
            2->{
                val res = ratting - i;
                if(res >= 1){
                    Log.d(TAG, "start 3")
                    getDrawable(R.drawable.full)?.let { expandHorizontal(star3, it) }
                }
                else if(res > 0 && res < 1){
                    Log.d(TAG, "start three and half")
                    getDrawable(R.drawable.half)?.let { expandHorizontal(star3, it) }
                }
                else{
                    Log.d(TAG, "no start")
                    getDrawable(R.drawable.empty)?.let { expandHorizontal(star3, it) }
                }
            }
            3 -> {
                val res = ratting - i;
                if(res >= 1){
                    Log.d(TAG, "start 4")
                    getDrawable(R.drawable.full)?.let { expandHorizontal(star4, it) }
                }
                else if(res > 0 && res < 1){
                    Log.d(TAG, "start 4 and half")
                    getDrawable(R.drawable.half)?.let { expandHorizontal(star4, it) }
                }
                else{
                    Log.d(TAG, "no start")
                    getDrawable(R.drawable.empty)?.let { expandHorizontal(star4, it) }
                }
            }
            4 ->{
                val res = ratting - i;
                if(res >= 1){
                    Log.d(TAG, "start 5")
                    getDrawable(R.drawable.full)?.let { expandHorizontal(star5, it) }
                }
                else if(res > 0 && res < 1){
                    Log.d(TAG, "start three and half")
                    getDrawable(R.drawable.half)?.let { expandHorizontal(star5, it) }
                }
                else{
                    Log.d(TAG, "no start")
                    getDrawable(R.drawable.empty)?.let { expandHorizontal(star5, it) }
                }
            }
        }
    }
}

您可以在 expandHorizo​​ntal 中选择动画

【讨论】:

    【解决方案2】:

    这里有一个小技巧,你可以做到这一点。一个带有背景颜色的图层会出现在您要隐藏的星星之上。我尝试更改评分栏的大小,但评分显示错误。

    activity_main.xml

    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="60dp"
        android:layout_marginTop="20dp">
    
        <androidx.appcompat.widget.AppCompatRatingBar
            android:id="@+id/ratingBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:isIndicator="true"
            android:rating="3.5"
            android:stepSize="0.1" />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:background="#ffffff"
            android:id="@+id/hideView"
            android:orientation="horizontal"
            android:layout_gravity="end"/>
    
    </FrameLayout>
    
    
    <Button
        android:id="@+id/button3_5Stars"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="Set rating to 3.5 star" />
    
    </LinearLayout>
    

    MainActivity.kt

    package com.example.test
    
    import android.os.Bundle
    import android.widget.Button
    import android.widget.LinearLayout
    import androidx.appcompat.app.AppCompatActivity
    import androidx.appcompat.widget.AppCompatRatingBar
    import kotlinx.coroutines.CoroutineScope
    import kotlinx.coroutines.Dispatchers
    import kotlinx.coroutines.delay
    import kotlinx.coroutines.launch
    import kotlin.math.ceil
    
    class MainActivity : AppCompatActivity() {
        var oneStarWidth:Int?=null
        lateinit var ratingBar: AppCompatRatingBar
        lateinit var hideView: LinearLayout
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            ratingBar=findViewById(R.id.ratingBar)
            hideView=findViewById(R.id.hideView)
            getSingleStarWidth()
            findViewById<Button>(R.id.button3_5Stars).setOnClickListener {
                CoroutineScope(Dispatchers.Main).launch {
                    ratingBar.rating=3.5F
                    expandTogivenRating(ratingBar.rating)
                    delay(1000)
                    collapseToSingleStar()
                }
            }
        }
    
    
        fun getSingleStarWidth(){
            if(oneStarWidth==null){
                ratingBar.post {
                    oneStarWidth=ratingBar.width/5
                    collapseToSingleStar()
                }
            }
        }
    
        fun collapseToSingleStar(){
            expandTogivenRating(1.0f)
        }
    
        fun expandTogivenRating(rating:Float){
    
            val ratingInt= ceil(rating.toDouble())
    
            val layoutParams=hideView.layoutParams
            layoutParams.width= ((5- ratingInt) * (oneStarWidth?:0)).toInt()
            hideView.layoutParams=layoutParams
    
        }
    }
    

    输出:-

    你可以改进命名、动画、处理协程中的一次性。这应该会给你一个粗略的想法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-06
      • 1970-01-01
      • 1970-01-01
      • 2011-01-09
      • 1970-01-01
      • 1970-01-01
      • 2015-12-26
      相关资源
      最近更新 更多