简体   繁体   English

Android:动画评级栏以扩大和缩小每颗星

[英]Android : Animate Rating Bar to expand and shrink each star

I have a rating bar that shows 5 stars that I want to animate by filing from 0 to 5 depending on the value of the rating passed into the view and for each star to expand in size and then shrink back to its original size per star that has been colored/filled in.我有一个评级栏,它显示 5 颗星,我想通过归档从 0 到 5 进行动画处理,具体取决于传递到视图中的评级值,并且每颗星的大小扩大,然后缩小到每颗星的原始大小已着色/填充。

For example, all 4 stars out of 5 should expand and shrink back down on a star rating of 3.5 as an example.例如,5 颗星中的所有 4 颗星都应该以 3.5 的星级为例进行扩展和缩小。

I have got it to fill from 0 to 3.5 fine with the code below but have no idea how to expand each star that has some filled applied to it?我已经用下面的代码将它从 0 填充到 3.5,但不知道如何扩展每个应用了填充的星星?

Is this possible?这可能吗?

Here is what I have so far:这是我到目前为止所拥有的:

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

Add a container to hold five image view with default image.添加一个容器来保存五个带有默认图像的图像视图。

<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>

Then add animator然后添加动画师

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()
}

Call set star value when ever needed在需要时调用设置星值

 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) }
                }
            }
        }
    }
}

You can chose animation in expandHorizontal您可以在 expandHorizontal 中选择 animation

在此处输入图像描述

Here is a little hackish way you can do it.这是一个有点hackish的方法,你可以做到这一点。 A layer with background color appears on top of the stars you want to hide.带有背景颜色的图层会出现在您要隐藏的星星之上。 I tried changing size of rating bar but the rating shows up wrong.我尝试更改评分栏的大小,但评分显示错误。

activity_main.xml 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 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

    }
}

Output:- Output:-

在此处输入图像描述

You can to improve the naming, animation, handle the disposable from coroutines.您可以改进命名,animation,处理协程中的一次性。 This should give you a rough idea.这应该给你一个粗略的想法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM