[英]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.