仿美团评论等级

下载链接:自定义笑脸评分条

要求实现效果如图:

这里写图片描述

试了在代码里根据rating更换style,发现做不到,搜了半天我是不会。美团的评价有这个样式,就反编译了一下美团apk,没看到具体的java文件,倒是看到了它的attrs.xml,原来他是自定义的,然后网上搜了搜还是没找到自定义的符合要求的,不过可能是我的关键字不对,不太会搜索。所以打算自己试着自定义一个,正好一直没自己玩过,学学高科技。

误区:

刚开始自定义的时候看了一些书,这个时候就发现大佬们的优秀与亲民了,特别喜欢他们开篇会说其实自定义一点儿都不难,搞得我很有信心继续搞下去。真喜欢他们。高高兴兴继续往下看。
明白了一些理论与很多定义,做的时候理所当然的就继承RatingBar去做了,觉得就是在原有基础上扩展写内容嘛!后来遇到问题了,根据rating换背景倒是可以实现,可始终只有一个笑脸,不能出现五个,没有头绪了。努力了半天不会搞,最后想最笨大不了就自己造吧,画个linearLayout包五个星星来呗。

最终实现:

1. 第一步当然是attrs.xml

    <!--星级自定义属性-->
    <declare-styleable name="ThirdRatingBarView">
        <attr name="dividerWidth" format="dimension" />//间距
        <attr name="default_icon" format="reference" />//默认图标
        <attr name="selection_icon_bad" format="reference" />//差评图标
        <attr name="selection_icon_good" format="reference" />//好评图标
        <attr name="selection_icon_half_bad" format="reference" />//半星差图标
        <attr name="selection_icon_half_good" format="reference" />//半星好图标
        <attr name="starImageSize" format="float" />//星星大小
        <attr name="starCount" format="integer" />//星星数量
        <attr name="rating" format="float" />//当前评级
    </declare-styleable>

2. xml引用

    <com.yuanli.threeratingbar.widget.ThreeLevelRatingBarView
        android:id="@+id/ratingTotal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="20dp"
        app:default_icon="@mipmap/evaluate_default_face"
        app:rating="1.36"
        android:layout_toRightOf="@+id/tv_1"
        app:selection_icon_bad="@drawable/rating_bar_bad_smile"
        app:selection_icon_good="@drawable/rating_bar"
        app:selection_icon_half_good="@mipmap/evaluate_yellow_half"
        app:selection_icon_half_bad="@mipmap/evaluate_bad_face_half"
        app:starCount="5"
        app:starImageSize="96"/>

3. 自定义的java文件

傻瓜式注释都能看懂

package com.yuanli.threeratingbar.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.yuanli.threeratingbar.R;


/**
 * 项目名称:esparclientios
 * 创建人:李元利
 * 创建时间:2017/9/20 16:10
 * 描述:三级评价样式
 */

public class ThreeLevelRatingBarView extends LinearLayout {

    private String TAG = "RatingBar";

    //点击回调接口,监听用户设置的数量
    private OnRatingBarChangeListener onRatingBarChangeListener;

    public interface OnRatingBarChangeListener {
        void onRatingChanged(float RatingScore);
    }

    public void setOnRatingBarChangeListener(OnRatingBarChangeListener onRatingBarChangeListener) {
        this.onRatingBarChangeListener = onRatingBarChangeListener;
    }

    private boolean mClickable = true;

    //设置可否点击
    public void setClickable(boolean clickable) {
        this.mClickable = clickable;
    }

    //默认间距、大小、数量
    private static final int DEFAULT_DIVIDER_WIDTH = 0;
    private static final int DEFAULT_STAR_SIZE = 50;
    private static final int DEFAULT_STAR_COUNT = 5;

    private int mDividerWidth = DEFAULT_DIVIDER_WIDTH;
    private float starImageSize = DEFAULT_STAR_SIZE;
    private int starCount = DEFAULT_STAR_COUNT;
    private float mStarCount;

    private float rating;

    private Drawable starDrawable;
    private Drawable starDrawablehalf;

    private Drawable selection_icon_bad;
    private Drawable selection_icon_good;
    private Drawable selection_icon_half_bad;
    private Drawable selection_icon_half_good;
    private Drawable default_icon;

    public ThreeLevelRatingBarView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setOrientation(LinearLayout.HORIZONTAL);
        //获取自定义属性集
        TypedArray typedArray = context.obtainStyledAttributes(
                attrs, R.styleable.ThirdRatingBarView);
        //从TypedArray取出对应的值来为要设置的属性赋值
        default_icon = typedArray.getDrawable(R.styleable.ThirdRatingBarView_default_icon);
        selection_icon_bad = typedArray.getDrawable(R.styleable.ThirdRatingBarView_selection_icon_bad);
        selection_icon_good = typedArray.getDrawable(R.styleable.ThirdRatingBarView_selection_icon_good);
        selection_icon_half_bad = typedArray.getDrawable(R.styleable.ThirdRatingBarView_selection_icon_half_bad);
        selection_icon_half_good = typedArray.getDrawable(R.styleable.ThirdRatingBarView_selection_icon_half_good);
        mDividerWidth = typedArray.getDimensionPixelSize(R.styleable.ThirdRatingBarView_dividerWidth, DEFAULT_DIVIDER_WIDTH);
        starImageSize = typedArray.getFloat(R.styleable.ThirdRatingBarView_starImageSize, DEFAULT_STAR_SIZE);//星星大小
        starCount = typedArray.getInteger(R.styleable.ThirdRatingBarView_starCount, DEFAULT_STAR_COUNT);//星星总数
        rating = typedArray.getFloat(R.styleable.ThirdRatingBarView_rating, 0);
        typedArray.recycle();

        //画几个星星?
        for (int i = 0; i < starCount; ++i) {
            StarView imageView = getStarImageView(context,i);
            imageView.setOnStarViewChangeListener(new StarView.OnStarViewChangeListener() {
                @Override
                public void onViewChanged(float RatingScore, int size) {
                    if (mClickable) {//是否可点击
                        //获取子view的位置
                        mStarCount = size + RatingScore;//带小数的rating
                        setRating(mStarCount);

                        if (onRatingBarChangeListener != null) {
                            onRatingBarChangeListener.onRatingChanged(mStarCount);
                        }
                    }
                }
            });

//            imageView.setOnClickListener(new OnClickListener() {
//                @Override
//                public void onClick(View v) {
//                    if (mClickable) {//是否可点击
//                        //获取子view的位置
//                        mStarCount = indexOfChild(v) + 1;//只能是整数rating
//                        setRating(mStarCount);
//
//                        if (onRatingBarChangeListener != null) {
//                            onRatingBarChangeListener.onRatingChanged(mStarCount);
//                        }
//                    }
//                }
//            });
            addView(imageView);
        }

        setRating(rating);
    }


    //画一个星星
    private StarView getStarImageView(Context context,int i) {
        StarView imageView = new StarView(context,i);
        ViewGroup.LayoutParams para = new ViewGroup.LayoutParams(
                Math.round(starImageSize), Math.round(starImageSize));
        imageView.setLayoutParams(para);
        imageView.setPadding(0, 0, mDividerWidth, 0);
        imageView.setImageDrawable(default_icon);
        imageView.setMaxWidth(24);
        imageView.setMaxHeight(24);
        return imageView;
    }

    //设置星星数
    public void setRating(float starCount) {
        //大于总数用自己,小于0用0(写完了发现网上有例子,优化下)
        starCount = starCount > this.starCount ? this.starCount : starCount;
        starCount = starCount < 0 ? 0 : starCount;

        rating = starCount;

        float decimals_count = starCount - (int) (starCount); //计算分数的小数部分
        int interger_count = (int) starCount; //计算分数的整数部分

        if (starCount <= 1) {
            starDrawable = selection_icon_bad;
            starDrawablehalf=selection_icon_half_bad;
        } else {
            starDrawable = selection_icon_good;
            starDrawablehalf=selection_icon_half_good;
        }


        //这里为了设置半星的图而准备,现在没有半星的图片,先这样,逻辑已有,到时候微调一下

        //先把整数外的其他行星设为空
        for (int i = this.starCount - 1; i >= interger_count; --i) {
            ((ImageView) getChildAt(i)).setImageDrawable(default_icon);
        }

        if (decimals_count > 0) {//如果有小数
            //整数设为全图
            for (int i = 0; i < interger_count; ++i) {
                ((ImageView) getChildAt(i)).setImageDrawable(starDrawable);
            }
            //最后一个设为半星的(四舍五入)
            if (decimals_count < 0.5)
                ((ImageView) getChildAt(interger_count)).setImageDrawable(starDrawablehalf);
            else
                ((ImageView) getChildAt(interger_count)).setImageDrawable(starDrawable);
        } else {//如果是整数,直接上背景
            for (int i = 0; i < starCount; ++i) {
                ((ImageView) getChildAt(i)).setImageDrawable(starDrawable);
            }

        }


    }

    //以下均可由代码设置
    public float getStarCount() {
        return mStarCount;
    }

    public void setSelection_icon_bad(Drawable selection_icon_bad) {
        this.selection_icon_bad = selection_icon_bad;
    }

    public void setSelection_icon_good(Drawable selection_icon_good) {
        this.selection_icon_good = selection_icon_good;
    }

    public void setDefault_icon(Drawable default_icon) {
        this.default_icon = default_icon;
    }

    public void setStarCount(int startCount) {
        this.starCount = startCount;
    }

    public void setStarImageSize(float starImageSize) {
        this.starImageSize = starImageSize;
    }

    public float getRating() {
        return rating;
    }
}

4. StarView

package com.yuanli.threeratingbar.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;

/**
 * 项目名称:ThreeRatingBar
 * 创建人:李元利
 * 创建时间:2017/10/9 17:44
 * 描述:获取点击的比例
 */

@SuppressLint("AppCompatCustomView")
public class StarView extends ImageView implements View.OnTouchListener {

    private String TAG = "RatingBar";

    private Context mContext;
    private GestureDetector mGestureDetector;

    private float rating;
    private int size;

    //点击回调接口,监听用户设置的数量
    private StarView.OnStarViewChangeListener onStarViewChangeListener;

    public interface OnStarViewChangeListener {
        void onViewChanged(float RatingScore,int size);
    }

    public void setOnStarViewChangeListener(StarView.OnStarViewChangeListener onStarViewChangeListener) {
        this.onStarViewChangeListener = onStarViewChangeListener;
    }


    public StarView(Context context,int i) {
        super(context);
        this.size=i;
        initData(context);
    }



    private void initData(Context context) {
        this.mContext = context;
        super.setOnTouchListener(this);
        super.setClickable(true);
        super.setLongClickable(true);
        super.setFocusable(true);
        mGestureDetector = new GestureDetector(mContext, new MyGestureListener());
        mGestureDetector.setOnDoubleTapListener(new MyGestureListener());
    }

    /*
       * 当该view上的事件被分发到view上时触发该方法的回调
       * 如果这个方法返回false时,该事件就会被传递给Activity中的onTouchEvent方法来处理
       * 如果该方法返回true时,表示该事件已经被onTouch函数处理玩,不会上传到activity中处理
       * 该方法属于View.OnTouchListening接口
       * */
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return mGestureDetector.onTouchEvent(event);
    }

    /*
    *
    * 手势监听类
    * */
    class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
        public MyGestureListener() {
            super();
        }


        @Override
        /*
        *每按一下屏幕立即触发
        * */
        public boolean onDown(MotionEvent e) {
            Log.e(TAG, "onDown");
            return false;
        }

        @Override
        /*
        *用户按下屏幕并且没有移动或松开。主要是提供给用户一个可视化的反馈,告诉用户他们的按下操作已经
        * 被捕捉到了。如果按下的速度很快只会调用onDown(),按下的速度稍慢一点会先调用onDown()再调用onShowPress().
        * */
        public void onShowPress(MotionEvent e) {
            Log.e(TAG, "onShowPress");
        }

        @Override
        /*
        *一次单纯的轻击擡手动作时触发
        * */
        public boolean onSingleTapUp(MotionEvent e) {
            Log.e(TAG, "onSingleTapUp");
            //点击的位置比view的宽度来获取rating
            rating=e.getX()/getWidth();
            if(onStarViewChangeListener!=null){
                onStarViewChangeListener.onViewChanged(rating,size);
            }

            return false;
        }


    }
}

5. Activity引用

    @Bind(id.rate_communicate)
    ThreeLevelRatingBarView rateCommunicate;
    
//禁止再点击
rateCommunicate.setClickable(false);
//获取并设置rating
CommunicationScore = rateCommunicate.getRating() + "";

rateCommunicate.setRating(Float.parseFloat(CommunicationScore));

//点击监听
rateCommunicate.setOnRatingBarChangeListener(new ThreeLevelRatingBarView.OnRatingBarChangeListener() {
            @Override
            public void onRatingChanged(float RatingScore) {
                if (RatingScore > 2) {
                    tvCommunicate.setText("好");
                } else if (RatingScore <= 1) {
                    tvCommunicate.setText("差");
                } else {
                    tvCommunicate.setText("一般");
                }
            }
        });

下载链接:自定义笑脸评分条

发布了48 篇原创文章 · 获赞 12 · 访问量 5万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章