Recent Posts
밍쯔와 안작고 안귀여운 에러들🖤
[Android] Custom RatingBar - star : png to svg 본문
[문제]
png로 android 기존의 rating bar를 사용하면
깨지는 경우가 너무 많다,,,,,!! 여러모로 퀄리티를 높이기 위해 png가 아닌 svg로 사용할 수 있도록 작업했다.
[해결]
https://github.com/Malligan/RatingBarSvg
기본적으로는 위의 git을 참고했다.
다만 문제는 위의 코드를 그대로 사용하면
wrap_content가 제대로 적용되지 않고 높이가 svg보다 훨씬 큰걸 알 수 있다.
이를 해결하기 위해 view의 사이즈를 결정하는 함수 내 height 결정값을 변경해줬고,
default wrap_content의 사이즈가 제대로 적용된 것을 볼 수 있다.
아래는 적용한 custom RatingBar의 적용하는 소스 코드다.
activity/fragment xml
<com.....RatingBarSvg
android:progressDrawable="@drawable/ic_star_large_pink"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:numStars="5"
android:stepSize="1"/>
ic_star_large_pink(selector) xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@android:id/background"
android:drawable="@drawable/ic_star_large_gray" />
<item
android:id="@android:id/secondaryProgress"
android:drawable="@drawable/ic_star_large_gray" />
<item
android:id="@android:id/progress"
android:drawable="@drawable/ic_star_pink_large" />
</layer-list>
Custom RatingBarSvg
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapShader
import android.graphics.Canvas
import android.graphics.Shader
import android.graphics.drawable.*
import android.graphics.drawable.shapes.RoundRectShape
import android.graphics.drawable.shapes.Shape
import android.util.AttributeSet
import android.view.Gravity
import androidx.appcompat.graphics.drawable.DrawableWrapper
import androidx.appcompat.widget.AppCompatRatingBar
class RatingBarSvg @JvmOverloads constructor(
context: Context,
attrs : AttributeSet? = null,
defStyleAttr : Int = R.attr.ratingBarStyle
) : AppCompatRatingBar(context, attrs, defStyleAttr) {
private var mSampleTile : Bitmap? = null
private val drawableShape : Shape
get() {
val roundedCorners = floatArrayOf(5f, 5f, 5f, 5f, 5f, 5f, 5f, 5f)
return RoundRectShape(roundedCorners, null, null)
}
init {
val drawable = tileify(progressDrawable, false) as LayerDrawable
progressDrawable = drawable
}
/**
* Converts a drawable to a tiled version of itself. It will recursively
* traverse layer and state list drawables.
*/
@SuppressLint("RestrictedApi")
private fun tileify(drawable: Drawable, clip : Boolean) : Drawable {
if (drawable is DrawableWrapper) {
var inner: Drawable? = drawable.wrappedDrawable
if (inner != null) {
inner = tileify(inner, clip)
drawable.wrappedDrawable = inner
}
} else if (drawable is LayerDrawable) {
val numberOfLayers = drawable.numberOfLayers
val outDrawables = arrayOfNulls<Drawable>(numberOfLayers)
for (i in 0 until numberOfLayers) {
val id = drawable.getId(i)
outDrawables[i] = tileify(
drawable.getDrawable(i),
id == android.R.id.progress || id == android.R.id.secondaryProgress
)
}
val newBg = LayerDrawable(outDrawables)
for (i in 0 until numberOfLayers) {
newBg.setId(i, drawable.getId(i))
}
return newBg
} else if (drawable is BitmapDrawable) {
val tileBitmap = drawable.bitmap
if (mSampleTile == null) {
mSampleTile = tileBitmap
}
val shapeDrawable = ShapeDrawable(drawableShape)
val bitmapShader = BitmapShader(
tileBitmap,
Shader.TileMode.REPEAT, Shader.TileMode.CLAMP
)
shapeDrawable.paint.shader = bitmapShader
shapeDrawable.paint.colorFilter = drawable.paint.colorFilter
return if (clip)
ClipDrawable(
shapeDrawable, Gravity.LEFT,
ClipDrawable.HORIZONTAL
)
else
shapeDrawable
} else {
return tileify(getBitmapDrawableFromVectorDrawable(drawable), clip)
}
return drawable
}
private fun getBitmapDrawableFromVectorDrawable(drawable: Drawable): BitmapDrawable {
val bitmap = Bitmap.createBitmap(
drawable.intrinsicWidth + (2).toInt(),
drawable.intrinsicHeight,
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
drawable.draw(canvas)
return BitmapDrawable(resources, bitmap)
}
@Synchronized
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
if (mSampleTile != null) {
val width = mSampleTile!!.width * numStars
setMeasuredDimension(
resolveSizeAndState(width, widthMeasureSpec, 0),
resolveSizeAndState(mSampleTile!!.height, heightMeasureSpec, 0)
)
}
}
}
'Develop > Android | iOS' 카테고리의 다른 글
[Android] material TabLayout - tabBackground를 동적으로(programmatically) 변경하기 (1) | 2024.01.04 |
---|---|
[Android/Java] object 리스트 특정 값으로 중복제거 (2) | 2024.01.03 |
[Android] APK33(android 13) 수정 시 Permission 권한 요청 수정 (0) | 2023.09.08 |
[Android/Java] 토스 페이먼츠 SDK 적용하기 : SDK 추가하기 (0) | 2023.09.06 |
[Android/Java] wrap_content 오류 : ViewPager2 그리고 FragmentStateAdapter(fragment)_동적 높이 변환 (0) | 2023.08.22 |