Как создать панель пользовательских рейтингов в Android
Привет всем, что мне нужно для выполнения рейтинга в моем приложении... ТАК, мне нужно создать собственную панель рейтингов... Может ли кто-нибудь помочь мне в этом?
14 ответов
редактировать
Посмотрите на пользовательский рейтинг в Motorola http://community.developer.motorola.com/t5/Android-App-Development-for/custom-rating-bar-style-using-android-s-ratingBar-small-style/td-p/10462
обновленный
styles.xml
Это должно находиться в вашей папке значений
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="foodRatingBar" parent="@android:style/Widget.RatingBar">
<item name="android:progressDrawable">@drawable/food_rating_bar_full</item>
<item name="android:minHeight">23dip</item>
<item name="android:maxHeight">25dip</item>
</style>
</resources>
food_rating_bar_full.xml
Этот файл должен находиться в папке Drawable.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/background"
android:drawable="@drawable/food_ratingbar_full_empty" />
<item android:id="@+id/secondaryProgress"
android:drawable="@drawable/food_ratingbar_full_empty" />
<item android:id="@+id/progress"
android:drawable="@drawable/food_ratingbar_full_filled" />
</layer-list>
food_ratingbar_full_empty.xml
Этот файл должен находиться внутри папки Drawable.
<?xml version="1.0" encoding="utf-8"?>
<!-- This is the rating bar drawable that is used to
show a filled cookie. -->
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:state_window_focused="true"
android:drawable="@drawable/cookiee" />
<item android:state_focused="true"
android:state_window_focused="true"
android:drawable="@drawable/cookiee" />
<item android:state_selected="true"
android:state_window_focused="true"
android:drawable="@drawable/cookiee" />
<item android:drawable="@drawable/cookiee" />
</selector>
food_ratingbar_full_filled.xml
Этот файл должен находиться в папке Drawable.
<?xml version="1.0" encoding="utf-8"?>
<!-- This is the rating bar drawable that is used to
show a unfilled cookie. -->
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:state_window_focused="true"
android:drawable="@drawable/cookie" />
<item android:state_focused="true"
android:state_window_focused="true"
android:drawable="@drawable/cookie" />
<item android:state_selected="true"
android:state_window_focused="true"
android:drawable="@drawable/cookie" />
<item android:drawable="@drawable/cookie" />
</selector>
Файл main.xml должен выглядеть так:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<RatingBar android:id="@+id/ratingBar1"
style="@style/foodRatingBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</RatingBar>
</LinearLayout>
MainActivity.class должен выглядеть так:
import android.app.Activity;
import android.os.Bundle;
import android.widget.RatingBar;
import android.widget.RatingBar.OnRatingBarChangeListener;
import android.widget.Toast;
public class MainActivity extends Activity {
/** Called when the activity is first created. */
RatingBar rb;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
rb=(RatingBar)findViewById(R.id.ratingBar1);
rb.setOnRatingBarChangeListener(new OnRatingBarChangeListener(){
@Override
public void onRatingChanged(RatingBar ratingBar, float rating,
boolean fromUser) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(),Float.toString(rating),Toast.LENGTH_LONG).show();
}
});
}
}
Я использовал два изображения:
cookie.jpg
cookiee.jpg
Эти два изображения имеют одинаковый размер: одно используется для идентификации выбранной панели рейтинга, а другое - для идентификации невыбранной панели рейтинга.
Мне нужно добавить свое решение, которое ПУТИ, что выше. Нам даже не нужно использовать стили.
Создайте файл селектора в папке drawable:
custom_ratingbar_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/star_off" />
<item android:id="@android:id/secondaryProgress"
android:drawable="@drawable/star_off" />
<item android:id="@android:id/progress"
android:drawable="@drawable/star_on" />
</layer-list>
В макете установите файл селектора как progressDrawable:
<RatingBar
android:id="@+id/ratingBar2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:progressDrawable="@drawable/custom_ratingbar_selector"
android:numStars="8"
android:stepSize="0.2"
android:rating="3.0" />
И это все, что нам нужно.
Сначала добавьте изображения в drawable:
первая картинка "ratingbar_staroff.png" и вторая "ratingbar_staron.png"
После этого создайте файл ratingbar.xml для res/drawable.
<?xml version="1.0" encoding="utf-8"?>
<!--suppress AndroidDomInspection -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+android:id/background"
android:drawable="@drawable/ratingbar_empty" />
<item android:id="@+android:id/secondaryProgress"
android:drawable="@drawable/ratingbar_empty" />
<item android:id="@+android:id/progress"
android:drawable="@drawable/ratingbar_filled" />
</layer-list>
следующий xml такой же на res/drawable
"Ratingbar_empty.xml"
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:state_window_focused="true"
android:drawable="@drawable/ratingbar_staroff" />
<item android:state_focused="true"
android:state_window_focused="true"
android:drawable="@drawable/ratingbar_staroff" />
<item android:state_selected="true"
android:state_window_focused="true"
android:drawable="@drawable/ratingbar_staroff" />
<item android:drawable="@drawable/ratingbar_staroff" />
</selector>
"Ratingbar_filled"
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:state_window_focused="true"
android:drawable="@drawable/ratingbar_staron" />
<item android:state_focused="true"
android:state_window_focused="true"
android:drawable="@drawable/ratingbar_staron" />
<item android:state_selected="true"
android:state_window_focused="true"
android:drawable="@drawable/ratingbar_staron" />
<item android:drawable="@drawable/ratingbar_staron" />
</selector>
затем нужно добавить эти строки кода в res/values /styles
<style name="CustomRatingBar" parent="@android:style/Widget.RatingBar">
<item name="android:progressDrawable">@drawable/ratingbar</item>
<item name="android:minHeight">18dp</item>
<item name="android:maxHeight">18dp</item>
</style>
Теперь уже можно добавить стиль в ресурс рейтинга
<RatingBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style= "@style/CustomRatingBar"
android:id="@+id/ratingBar"
android:numStars="5"
android:stepSize="0.01"
android:isIndicator="true"/>
В конце концов о вашей деятельности только объявите:
RatingBar ratingbar = (RatingBar) findViewById(R.id.ratingbar);
ratingbar.setRating(3.67f);
Для SVG RatingBar
Здесь я использовал наложение пользовательских рисованных объектов RatingBar и ответ erdomester. Это решение пересекает все чертежи внутри SvgRatingBar
вид вашего макета, так что в RecyclerView
это накладные расходы.
SvgRatingBar.java:
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.BitmapDrawable;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.VectorDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.graphics.drawable.shapes.Shape;
import android.os.Build;
import android.support.v7.graphics.drawable.DrawableWrapper;
import android.support.v7.widget.AppCompatRatingBar;
import android.util.AttributeSet;
import android.view.Gravity;
public class SvgRatingBar extends AppCompatRatingBar {
private Bitmap sampleTile;
public SvgRatingBar(Context context) {
this(context, null);
}
public SvgRatingBar(Context context, AttributeSet attrs) {
this(context, attrs, android.support.v7.appcompat.R.attr.ratingBarStyle);
}
public SvgRatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
LayerDrawable drawable = (LayerDrawable) createTile(getProgressDrawable(), false);
setProgressDrawable(drawable);
}
/**
* Converts a drawable to a tiled version of itself. It will recursively
* traverse layer and state list drawables.
*/
@SuppressLint("RestrictedApi")
private Drawable createTile(Drawable drawable, boolean clip) {
if (drawable instanceof DrawableWrapper) {
Drawable inner = ((DrawableWrapper) drawable).getWrappedDrawable();
if (inner != null) {
inner = createTile(inner, clip);
((DrawableWrapper) drawable).setWrappedDrawable(inner);
}
} else if (drawable instanceof LayerDrawable) {
LayerDrawable background = (LayerDrawable) drawable;
final int n = background.getNumberOfLayers();
Drawable[] outDrawables = new Drawable[n];
for (int i = 0; i < n; i++) {
int id = background.getId(i);
outDrawables[i] = createTile(background.getDrawable(i),
(id == android.R.id.progress || id == android.R.id.secondaryProgress));
}
LayerDrawable newBg = new LayerDrawable(outDrawables);
for (int i = 0; i < n; i++) {
newBg.setId(i, background.getId(i));
}
return newBg;
} else if (drawable instanceof BitmapDrawable) {
final BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
final Bitmap tileBitmap = bitmapDrawable.getBitmap();
if (sampleTile == null) {
sampleTile = tileBitmap;
}
final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
shapeDrawable.getPaint().setShader(bitmapShader);
shapeDrawable.getPaint().setColorFilter(bitmapDrawable.getPaint().getColorFilter());
return (clip) ? new ClipDrawable(shapeDrawable, Gravity.START,
ClipDrawable.HORIZONTAL) : shapeDrawable;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && drawable instanceof VectorDrawable) {
return createTile(getBitmapDrawableFromVectorDrawable(drawable), clip);
}
return drawable;
}
private BitmapDrawable getBitmapDrawableFromVectorDrawable(Drawable drawable) {
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return new BitmapDrawable(getResources(), bitmap);
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (sampleTile != null) {
final int width = sampleTile.getWidth() * getNumStars();
setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0),
getMeasuredHeight());
}
}
private Shape getDrawableShape() {
final float[] roundedCorners = new float[]{5, 5, 5, 5, 5, 5, 5, 5};
return new RoundRectShape(roundedCorners, null, null);
}
}
В вашем макете:
<com.example.common.control.SvgRatingBar
android:id="@+id/rate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="13dp"
android:numStars="5"
android:progressDrawable="@drawable/rating_bar"
android:rating="3.5"
android:stepSize="0.01"
/>
Вы также должны создать rating_bar.xml с двумя рисунками SVG:
<?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_unfilled_star"
/>
<item
android:id="@android:id/secondaryProgress"
android:drawable="@drawable/ic_unfilled_star"
/>
<item
android:id="@android:id/progress"
android:drawable="@drawable/ic_filled_star"
/>
</layer-list>
Создание пользовательского рейтингового бара со списком слоев и селекторами является сложным, лучше переопределить класс RatingBar и создать пользовательский RatingBar. createBackgroundDrawableShape() - это функция, в которую следует поместить пустое состояние png, а createProgressDrawableShape() - функция, в которую следует поместить заполненное состояние png.
Примечание. Этот код пока не будет работать с svg.
public class CustomRatingBar extends RatingBar {
@Nullable
private Bitmap mSampleTile;
public ShapeDrawableRatingBar(final Context context, final AttributeSet attrs) {
super(context, attrs);
setProgressDrawable(createProgressDrawable());
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mSampleTile != null) {
final int width = mSampleTile.getWidth() * getNumStars();
setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0), getMeasuredHeight());
}
}
protected LayerDrawable createProgressDrawable() {
final Drawable backgroundDrawable = createBackgroundDrawableShape();
LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{
backgroundDrawable,
backgroundDrawable,
createProgressDrawableShape()
});
layerDrawable.setId(0, android.R.id.background);
layerDrawable.setId(1, android.R.id.secondaryProgress);
layerDrawable.setId(2, android.R.id.progress);
return layerDrawable;
}
protected Drawable createBackgroundDrawableShape() {
final Bitmap tileBitmap = drawableToBitmap(getResources().getDrawable(R.drawable.ic_star_empty));
if (mSampleTile == null) {
mSampleTile = tileBitmap;
}
final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
final BitmapShader bitmapShader = new BitmapShader(tileBitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
shapeDrawable.getPaint().setShader(bitmapShader);
return shapeDrawable;
}
protected Drawable createProgressDrawableShape() {
final Bitmap tileBitmap = drawableToBitmap(getResources().getDrawable(R.drawable.ic_star_full));
final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
final BitmapShader bitmapShader = new BitmapShader(tileBitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
shapeDrawable.getPaint().setShader(bitmapShader);
return new ClipDrawable(shapeDrawable, Gravity.LEFT, ClipDrawable.HORIZONTAL);
}
Shape getDrawableShape() {
final float[] roundedCorners = new float[]{5, 5, 5, 5, 5, 5, 5, 5};
return new RoundRectShape(roundedCorners, null, null);
}
public static Bitmap drawableToBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
int width = drawable.getIntrinsicWidth();
width = width > 0 ? width : 1;
int height = drawable.getIntrinsicHeight();
height = height > 0 ? height : 1;
final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}
Я исследовал первоисточник,
и вот мой результат.
styles.xml (res / values)
<!-- RatingBar -->
<style name="RatingBar" parent="@android:style/Widget.RatingBar">
<item name="android:progressDrawable">@drawable/ratingbar_full</item>
<item name="android:indeterminateDrawable">@drawable/ratingbar_full</item>
<item name="android:minHeight">13.4dp</item>
<item name="android:maxHeight">13.4dp</item>
</style>
ratingbar_full.xml (res / drawable)
<?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/btn_rating_star_off_normal" />
<item android:id="@android:id/secondaryProgress" android:drawable="@drawable/btn_rating_star_off_normal" />
<item android:id="@android:id/progress" android:drawable="@drawable/btn_rating_star_on_normal" />
</layer-list>
btn_rating_star_off_normal.png (res / drawable-xxhdpi)
btn_rating_star_on_normal.png (res / drawable-xxhdpi)
activity_ratingbar.xml (res / layout)
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatRatingBar
android:id="@+id/ratingbar"
style="@style/RatingBar"
android:layout_width="wrap_content"
android:layout_height="13.4dp"
android:isIndicator="false"
android:numStars="5"
android:rating="2.6"
android:secondaryProgressTint="#00000000"
android:stepSize="0.1" />
</FrameLayout>
Это результат.
- Обратите внимание, что я добавил фактическую высоту (13.4dp) рейтинга в
layout_height
собственности, потому что если этоwrap_content
это будет рисовать линии под звездами. (в моем случае только в превью Android Studio)
Я сделал что-то похожее, RatingBar с отдельными значками рейтинга, я использую VectorDrawables для значков рейтинга, но вы можете использовать любой тип рисования
Следующий код работает:
@Override
protected synchronized void onDraw(Canvas canvas)
{
int stars = getNumStars();
float rating = getRating();
try
{
bitmapWidth = getWidth() / stars;
}
catch (Exception e)
{
bitmapWidth = getWidth();
}
float x = 0;
for (int i = 0; i < stars; i++)
{
Bitmap bitmap;
Resources res = getResources();
Paint paint = new Paint();
if ((int) rating > i)
{
bitmap = BitmapFactory.decodeResource(res, starColor);
}
else
{
bitmap = BitmapFactory.decodeResource(res, starDefault);
}
Bitmap scaled = Bitmap.createScaledBitmap(bitmap, getHeight(), getHeight(), true);
canvas.drawBitmap(scaled, x, 0, paint);
canvas.save();
x += bitmapWidth;
}
super.onDraw(canvas);
}
Вы можете создать собственную панель оценки материала, определив нарисованный XML-файл, используя выбранный вами значок материала, а затем применив настраиваемое изображение к панели оценки с помощью атрибута progressDrawable.
Информацию о настройке строки рейтинга см. На http://www.zoftino.com/android-ratingbar-and-custom-ratingbar-example
Внизу отрисовываемого 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">
<bitmap
android:src="@drawable/thumb_up"
android:tint="?attr/colorControlNormal" />
</item>
<item android:id="@android:id/secondaryProgress">
<bitmap
android:src="@drawable/thumb_up"
android:tint="?attr/colorControlActivated" />
</item>
<item android:id="@android:id/progress">
<bitmap
android:src="@drawable/thumb_up"
android:tint="?attr/colorControlActivated" />
</item>
</layer-list>
Другой подход (в разработке)
Просто для развлечения:
Плюсы: Поддерживает
Минусы: поддерживает только целочисленные рейтинги (средний рейтинг должен быть целым числом).
<style name="RatingButtonStyle" parent="Widget.Material3.Button.Icon">
<item name="backgroundTint">@color/transparent</item>
<item name="iconTint">@color/selector_text_color</item>
<item name="iconGravity">textTop</item>
<item name="iconPadding">0dp</item>
<item name="iconSize">20dp</item>
<item name="android:padding">0dp</item>
<item name="android:insetLeft">0dp</item>
<!--<item name="android:insetTop">0dp</item>-->
<item name="android:insetBottom">0dp</item>
<item name="android:insetRight">0dp</item>
</style>
<com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/ratingToggleGroup"
android:layout_width="100dp"
android:layout_height="24dp"
app:singleSelection="false">
<com.google.android.material.button.MaterialButton
android:id="@+id/ratingButton1"
style="@style/RatingButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
app:icon="@drawable/ic_star_rounded_fill" />
<com.google.android.material.button.MaterialButton
android:id="@+id/ratingButton2"
style="@style/RatingButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
app:icon="@drawable/ic_star_rounded_fill" />
<com.google.android.material.button.MaterialButton
android:id="@+id/ratingButton3"
style="@style/RatingButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
app:icon="@drawable/ic_star_rounded_fill" />
<com.google.android.material.button.MaterialButton
android:id="@+id/ratingButton4"
style="@style/RatingButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
app:icon="@drawable/ic_star_rounded_fill" />
<com.google.android.material.button.MaterialButton
android:id="@+id/ratingButton5"
style="@style/RatingButtonStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
app:icon="@drawable/ic_star_rounded_fill" />
</com.google.android.material.button.MaterialButtonToggleGroup>
void showRatingBar(MaterialButton mButton1,
MaterialButton mButton2,
MaterialButton mButton3,
MaterialButton mButton4,
MaterialButton mButton5){
mButton5.setOnClickListener(v -> {
if(mButton4.isChecked()){
mButton5.setChecked(true);
}
mButton4.setChecked(false);
mButton3.setChecked(false);
mButton2.setChecked(false);
mButton1.setChecked(false);
});
mButton4.setOnClickListener(v -> {
if(mButton3.isChecked()){
mButton4.setChecked(true);
}
mButton5.setChecked(true);
mButton3.setChecked(false);
mButton2.setChecked(false);
mButton1.setChecked(false);
});
mButton3.setOnClickListener(v -> {
if(mButton2.isChecked()){
mButton3.setChecked(true);
}
mButton5.setChecked(true);
mButton4.setChecked(true);
mButton2.setChecked(false);
mButton1.setChecked(false);
});
mButton2.setOnClickListener(v -> {
if(mButton1.isChecked()){
mButton2.setChecked(true);
}
mButton5.setChecked(true);
mButton4.setChecked(true);
mButton3.setChecked(true);
mButton1.setChecked(false);
});
mButton1.setOnClickListener(v -> {
mButton5.setChecked(true);
mButton4.setChecked(true);
mButton3.setChecked(true);
mButton2.setChecked(true);
});
}
Вы можете использовать данное решение @erdomester для этого. Но если вы сталкиваетесь с проблемами с высотой строки рейтинга, то вы можете использовать высоту значков панели рейтинга программно.
В Котлине
val drawable = ContextCompat.getDrawable(context, R.drawable.rating_filled)
val drawableHeight = drawable.intrinsicHeight
rating_bar.layoutParams.height = drawableHeight
При создании пользовательской рейтинговой панели, которая отображает сплошную градиентную линию, идущую по треку, похожему на SeekBar, а не по звездам, я также столкнулся с проблемой, связанной с вертикальным центрированием фона (прорисовка трека). Это некорректный отрисовываемый код, который я использовал изначально (который породил проблему), как это было предложено разработчиком Android и другими записями Stackru:
<?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/seekbar_track"/>
<item android:id="@android:id/secondaryProgress">
<scale
android:drawable="@drawable/seekbar_progress2"
android:scaleWidth="100%" />
</item>
<item android:id="@android:id/progress" >
<clip android:clipOrientation="horizontal" android:gravity="left" >
<shape>
<gradient
android:startColor="@color/ratingbar_bg_start"
android:centerColor="@color/ratingbar_bg_center"
android:centerX="0.5"
android:endColor="@color/ratingbar_bg_end"
android:angle="0"
/>
</shape>
</clip>
</item>
</layer-list>
Проблема здесь заключается в первом элементе, который относится к фону пользовательского RatingBar. Многие записи скажут вам установить для layout_minHeight какое-то большое значение, чтобы избежать вертикального пространственного разъединения между большим пальцем и его дорожкой. Для меня это не было решением - при просмотре на планшете фон все еще уменьшался до меньшего размера, основанного на телефоне - поэтому дорожка постоянно располагалась значительно выше центра дорожки RatingBar. Решение состоит в том, чтобы удалить эту запись в рисовании RatingBar, так что теперь это выглядит так:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/secondaryProgress">
<scale
android:drawable="@drawable/seekbar_progress2"
android:scaleWidth="100%" />
</item>
<item android:id="@android:id/progress" >
<clip android:clipOrientation="horizontal" android:gravity="left" >
<shape>
<gradient
android:startColor="@color/ratingbar_bg_start"
android:centerColor="@color/ratingbar_bg_center"
android:centerX="0.5"
android:endColor="@color/ratingbar_bg_end"
android:angle="0"
/>
</shape>
</clip>
</item>
</layer-list>
Затем в определении стиля пользовательского RatingBar установите layout_background для прорисовки дорожки. Моя выглядит так:
<style name="styleRatingBar" parent="@android:style/Widget.RatingBar">
<item name="android:indeterminateOnly">false</item>
<item name="android:background">@drawable/seekbar_track</item>
<item name="android:progressDrawable">@drawable/abratingbar</item>
<item name="android:thumb">@drawable/abseekbar_thumb</item>
<item name="android:minHeight">@dimen/base_29dp</item>
<item name="android:maxHeight">@dimen/base_29dp</item>
<item name="android:layout_marginLeft">@dimen/base_10dp</item>
<item name="android:layout_marginRight">@dimen/base_10dp</item>
<item name="android:layout_marginTop">@dimen/base_10dp</item>
<item name="android:layout_marginBottom">@dimen/base_10dp</item>
<item name="android:scaleType">fitXY</item>
</style>
(Ранее настройка фона здесь была неопределенной.)
Это запись в моем макете, в которой используются как стиль, так и элементы рисования:
<RatingBar
android:id="@+id/ratingbar_vote"
style="@style/styleRatingBar"
android:hint="@string/ratingbar_vote"
android:contentDescription="@string/ratingbar_vote"
android:numStars="5"
android:rating="5"
android:stepSize="1"
android:layout_width="match_parent"
android:layout_height="@dimen/base_29dp"
android:layout_marginLeft="@dimen/base_120dp"
android:layout_gravity="bottom|right" />
Таким образом, чтобы подвести итог, не устанавливайте фоновую функцию (дорожку) в вашей настраиваемой области рисования RatingBar, установите ее в функции layout_background вашего собственного стиля RatingBar. Это гарантирует, что дорожка всегда центрирована вертикально в горизонтальной панели рейтинга. (Помните, что в этом пользовательском RatingBar вместо звездочек или других изолированных изображений в качестве рейтинга я использую градиентную линию, которая "растет" или "сжимается" по горизонтали для отображения рейтинга - в этой строке рейтинга используется большой палец, похожий на SeekBar работает на SeekBar-подобной "дорожке".)
Вы можете иметь 5 изображений с изображением по умолчанию в виде звезды, которая пуста, и заполнить строку рейтинга половиной или полным основанием изображения по рейтингу.
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View grid=inflater.inflate(R.layout.griditem, parent, false);
imageView=(ImageView)grid.findViewById(R.id.grid_prod);
imageView.setImageResource(imgId[position]);
imgoff =(ImageView)grid.findViewById(R.id.offer);
tv=(TextView)grid.findViewById(R.id.grid_text);
tv.setText(namesArr[position]);
tv.setTextColor(Color.BLACK);
tv.setPadding(0, 2, 0, 0);
sta=(ImageView)grid.findViewById(R.id.imageView);
sta1=(ImageView)grid.findViewById(R.id.imageView1);
sta2=(ImageView)grid.findViewById(R.id.imageView2);
sta3=(ImageView)grid.findViewById(R.id.imageView3);
sta4=(ImageView)grid.findViewById(R.id.imageView4);
Float rate=rateFArr[position];
if(rate==5 || rate==4.5)
{
sta.setImageResource(R.drawable.full__small);
sta1.setImageResource(R.drawable.full__small);
sta2.setImageResource(R.drawable.full__small);
sta3.setImageResource(R.drawable.full__small);
if(rate==4.5)
{
sta4.setImageResource(R.drawable.half_small);
}
else
{
sta4.setImageResource(R.drawable.full__small);
}
}
if(rate==4 || rate==3.5)
{
sta.setImageResource(R.drawable.full__small);
sta1.setImageResource(R.drawable.full__small);
sta2.setImageResource(R.drawable.full__small);
if(rate==3.5)
{
sta3.setImageResource(R.drawable.half_small);
}
else
{
sta3.setImageResource(R.drawable.full__small);
}
}
if(rate==3 || rate==2.5)
{
sta.setImageResource(R.drawable.full__small);
sta1.setImageResource(R.drawable.full__small);
if(rate==2.5)
{
sta2.setImageResource(R.drawable.half_small);
}
else
{
sta2.setImageResource(R.drawable.full__small);
}
}
if(rate==2 || rate==1.5)
{
sta.setImageResource(R.drawable.full__small);
if(rate==1.5)
{
sta1.setImageResource(R.drawable.half_small);
}
else
{
sta1.setImageResource(R.drawable.full__small);
}
}
if(rate==1 || rate==0.5)
{
if(rate==1)
sta.setImageResource(R.drawable.full__small);
else
sta.setImageResource(R.drawable.half_small);
}
if(rate>5)
{
sta.setImageResource(R.drawable.full__small);
sta1.setImageResource(R.drawable.full__small);
sta2.setImageResource(R.drawable.full__small);
sta3.setImageResource(R.drawable.full__small);
sta4.setImageResource(R.drawable.full__small);
}
// rb=(RatingBar)findViewById(R.id.grid_rating);
//rb.setRating(rateFArr[position]);
return grid;
}