Як створити спеціальну панель оцінок в Android


80

Привіт усім, що мені потрібно для оцінки в моїй програмі ... ТАК мені потрібно створити власну панель оцінок ... Чи може хтось мені допомогти в цьому?


6
Деякі фрагменти коду були б корисними (можливо, макетами вашої мети), щоб побачити, де ви перебуваєте. Дивлячись на ваш пост, це не схоже на проблему, яку потрібно вирішити. Більше пропозиції про роботу, будь ласка, детальніше розробіть це.
rekaszeru

Відповіді:


153

Редагувати

Погляньте на спеціальний рейтинг в 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

Ці два зображення однакового розміру, одне використовується для ідентифікації вибраного рядка оцінок, а інше для ідентифікації невибраного рядка оцінок


16
Це спрацювало для мене після зміни у файлі food_rating_bar_full.xml ідентифікаторів товару. Я замінив <item android: id = "@ + android: id / background" на <item android: id = "@ android: id / background" (без символу +).
Р. Кампос

1
перше посилання в дописі недоступне
Саймон Шнелл

1
Посилання не працює kozyr.zydako.net/2010/05/23/pretty-ratingbar
Jay Rathod RJ

4
те саме, що запропонував @erdomester, але більше коду. ПОПЕРЕДЖЕННЯ. Не забувайте, що це не працює з векторними зображеннями, лише з .png!
Кирило Кармазін

1
У мене не вийшло, але було добре, коли я замінив: - android: id = "@ + id / background на @android: id / background - android: id =" @ + id / secondaryProgress "на android: id = "@ android: id / secondaryProgress" - android: id = "@ + id / progress" з android: id = "@ android: id / progress"
Харіс Даутович,

56

Мені потрібно додати своє рішення, яке набагато ефективніше, ніж наведене вище. Нам навіть не потрібно використовувати стилі.

Створіть файл селектора в папці, яку можна малювати:

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

І це все, що нам потрібно.


1
+1, але вибачте, це повинно працювати, але ні. Спочатку ви сказали, що додаєте селектор, але насправді ви додаєте список шарів. По-друге, я точно спробував ваш код, але все, що я отримую - це порожній компонент (зображення взагалі відсутнє). Можливо, ви можете відповісти на моє запитання: stackoverflow.com/questions/14251092/… Подяка: D
Blaze Tama

3
Цей простий підхід призводить до проблем із позиціонуванням рейтингової смуги в макеті. Більш традиційний підхід до визначення стилю є кращим.
javaxian

3
він показує рядок внизу на всіх зірках рейтингової смуги
Суніл

3
Чудово працює, thx. ПОПЕРЕДЖЕННЯ. Не забувайте, що це не працює з векторними зображеннями, лише з .png!
Кирило Кармазін

Дякую! Для SVG див. Мою відповідь тут: stackoverflow.com/a/53589663/2914140 .
CoolMind

48

спочатку додайте зображення до малюваного:

введіть тут опис зображення введіть тут опис зображення

перша картинка "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>

"рейтинг_заповнено"

<?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);

введіть тут опис зображення


5
Це схоже на перевірену відповідь. Але має зображення (показує дробові зірки) та <! - придушити AndroidDomInspection -> у списку шарів. Натомість ви можете видалити знак плюса в "@ + android: id / background", щоб уникнути помилок Android. Також слід змінити minHeight та maxHeight на 50dp.
CoolMind

Дякую за рішення. Чи можу я знати, як ви налаштовуєте розмір зірок? мій підійшов дуже маленький. Дякую.
Джей

@jay в тому, що res/values/stylesвін визначає android:minHeightта android:maxHeightзмінює це, щоб збільшити розмір зірки
Inzimam Tariq IT

7

Створення власної панелі оцінок зі списком шарів та селекторами є складним, краще замінити клас 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;
    }
}

як можна збільшити простір між предметами?
Алі Резайян

1
@AliRezaiyan: Оскільки ми використовуємо власні малюнки, тобто ic_star_full та ic_star_empty, ви можете просто додати порожній простір (відступ) зліва та праворуч від вашого PNG. Ви можете використовувати такі інструменти, як GIMP або Android Asset Studio, щоб досягти цього, відредагувавши PNG. Сподіваюся, це допомагає.
Gaurav Saluja

Я шукаю програмний шлях
Алі Резайян

5

Для SVG RatingBar я використав користувальницькі накладання Rating Draw Vector Drawables та відповідь 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.util.AttributeSet;
import android.view.Gravity;

import androidx.appcompat.graphics.drawable.DrawableWrapper;
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;

import com.example.R; // Your R.java file for R.attr.ratingBarStyle.

public class SvgRatingBar extends androidx.appcompat.widget.AppCompatRatingBar {

    private Bitmap sampleTile;

    public SvgRatingBar(Context context) {
        this(context, null);
    }

    public SvgRatingBar(Context context, AttributeSet attrs) {
        this(context, attrs, 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);
        } else if (drawable instanceof VectorDrawableCompat) {
            // API 19 support.
            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>

введіть тут опис зображення

Якщо ви бачите в режимі дизайну / розділення лише одну зірку, оновіть макет:

введіть тут опис зображення

У Котліні.

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.os.Build
import android.util.AttributeSet
import android.view.Gravity
import androidx.appcompat.graphics.drawable.DrawableWrapper
import androidx.appcompat.widget.AppCompatRatingBar
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
import com.example.R; // Your R.java file for R.attr.ratingBarStyle.

class SvgRatingBar @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
                                             defStyleAttr: Int = R.attr.ratingBarStyle) :
    AppCompatRatingBar(context, attrs, defStyleAttr) {

    private var sampleTile: Bitmap? = null
    private val roundedCorners = floatArrayOf(5f, 5f, 5f, 5f, 5f, 5f, 5f, 5f)
    private val roundRectShape = RoundRectShape(roundedCorners, null, null)

    init {
        progressDrawable = createTile(progressDrawable, false) as LayerDrawable
    }

    /**
     * Converts a drawable to a tiled version of itself. It will recursively
     * traverse layer and state list drawables.
     */
    private fun createTile(drawable: Drawable, clip: Boolean): Drawable =
        when {
            drawable is DrawableWrapper -> {
                @SuppressLint("RestrictedApi")
                var inner = drawable.wrappedDrawable
                if (inner != null) {
                    inner = createTile(inner, clip)
                    @SuppressLint("RestrictedApi")
                    drawable.wrappedDrawable = inner
                }
                drawable
            }
            drawable is LayerDrawable -> {
                val n = drawable.numberOfLayers
                val outDrawables = arrayOfNulls<Drawable>(n)
                for (i in 0 until n) {
                    val id = drawable.getId(i)
                    outDrawables[i] = createTile(drawable.getDrawable(i),
                        id == android.R.id.progress || id == android.R.id.secondaryProgress)
                }
                val newBg = LayerDrawable(outDrawables)
                for (i in 0 until n) {
                    newBg.setId(i, drawable.getId(i))
                }
                newBg
            }
            drawable is BitmapDrawable -> {
                val tileBitmap = drawable.bitmap
                if (sampleTile == null) {
                    sampleTile = tileBitmap
                }
                val bitmapShader = BitmapShader(tileBitmap, Shader.TileMode.REPEAT,
                    Shader.TileMode.CLAMP)
                val shapeDrawable = ShapeDrawable(roundRectShape).apply {
                    paint.shader = bitmapShader
                    paint.colorFilter = drawable.paint.colorFilter
                }
                if (clip) ClipDrawable(shapeDrawable, Gravity.START, ClipDrawable.HORIZONTAL)
                else shapeDrawable
            }
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && drawable is VectorDrawable -> {
                createTile(getBitmapDrawableFromVectorDrawable(drawable), clip)
            }
            drawable is VectorDrawableCompat -> {
                // Pre-Lollipop support.
                createTile(getBitmapDrawableFromVectorDrawable(drawable), clip)
            }
            else -> drawable
        }

    private fun getBitmapDrawableFromVectorDrawable(drawable: Drawable): BitmapDrawable {
        val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight,
            Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, canvas.width, canvas.height)
        drawable.draw(canvas)
        return BitmapDrawable(resources, bitmap)
    }

    @Synchronized override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        if (sampleTile != null) {
            val width = sampleTile!!.width * numStars
            setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0),
                measuredHeight)
        }
    }
}

@Michalsx, дякую, удачі! Додана версія Kotlin.
CoolMind


4

Я дослідив першоджерело,
і ось мій результат.

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)

3

Я зробив щось подібне, RatingBar з окремими піктограмами оцінок, я використовую VectorDrawables для піктограм оцінки, але ви можете використовувати будь-який тип малюваного

https://github.com/manmountain/emoji-ratingbar

введіть тут опис зображення


2

Працює такий код:

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

1

Ви можете створити власний рядок оцінки матеріалу, визначивши малювальний 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>

0

Створюючи спеціальний рядок оцінки, який відображає суцільну градієнтну лінію, що працює на доріжці, подібній до SeekBar, а не зірками, я також зіткнувся з проблемою, пов'язаною з вертикальним центруванням фону (доріжка, що малюється). Це несправний код, який можна малювати, який я використовував спочатку (що породило проблему), як запропонував розробник Android та інші записи StackOverflow:

<?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. Рішення полягає в тому, щоб видалити цей запис у рейтинговій панелі, що можна малювати, тому він тепер виглядає так:

<?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.)


0

Ви можете використовувати для цього рішення @erdomester. Але якщо ви стикаєтесь із проблемами з висотою рядка оцінок, тоді ви можете використовувати програмну висоту значків оцінки.

У Котліні,

val drawable = ContextCompat.getDrawable(context, R.drawable.rating_filled)
val drawableHeight = drawable.intrinsicHeight

rating_bar.layoutParams.height = drawableHeight

Я також стикався з цією проблемою, але додав android:minHeightу макеті. Якщо програмно змінити, слід додати rating_bar.requestLayout().
CoolMind

-11

Ви можете мати 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;
    }

Це не спосіб зробити це. Для цього потрібно RatingBarвіджет. Крім того, це не те, що запитує OP.
4gus71n
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.