Android 制作类似RatingBar的组件

Android 制作类似RatingBar的组件,android,ontouchlistener,motionevent,ratingbar,Android,Ontouchlistener,Motionevent,Ratingbar,我需要显示一组点(ImageView),它们的行为类似于分级栏,下面是一个示例: 这几乎是一个旋转的分级条,但我有一个问题,这个应用程序是像素完美的,因此我需要在点之间添加一些边距。这不能通过分级条来完成。由于我在尝试使用RatingBar时遇到了所有这些问题,我放弃了,决定制作自己的组件,到目前为止,这就是组件: public class DotContainerView extends LinearLayout { @InjectView(R.id.view_dot_contai

我需要显示一组点(
ImageView
),它们的行为类似于
分级栏
,下面是一个示例:

这几乎是一个旋转的
分级条,但我有一个问题,这个应用程序是像素完美的,因此我需要在点之间添加一些边距。这不能通过
分级条来完成。由于我在尝试使用
RatingBar
时遇到了所有这些问题,我放弃了,决定制作自己的组件,到目前为止,这就是组件:

public class DotContainerView extends LinearLayout {

    @InjectView(R.id.view_dot_container)
    LinearLayout vDotContainer;

    private OnRatingBarChangeListener mListener;

    public DotContainerView(Context context) {
        super(context);
        initialize();
    }

    public DotContainerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize();
    }

    public DotContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initialize();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public DotContainerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initialize();
    }

    private void initialize() {
        View root = LayoutInflater.from(getContext()).inflate(R.layout.view_dot_container, this);
        ButterKnife.inject(this, root);
        setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                v.onTouchEvent(event);
                return false;
            }
        });
    }

    public void setRating(int rating) {
        for (int index = 0; index < rating; index++) {
            vDotContainer.getChildAt(index).setSelected(false);
        }
        for (int index = rating; index < 10; index++) {
            vDotContainer.getChildAt(index).setSelected(true);
        }
    }

    public void setOnRatingBarChangeListener(DotContainerView.OnRatingBarChangeListener listener) {
        mListener = listener;
    }

    //region OnTouch
    @OnTouch(R.id.fragment_brightness_control_dot_1)
    public boolean onDot1Touched() {
        setRating(1);
        mListener.onRatingChanged(this, 1, true);
        return true;
    }

    @OnTouch(R.id.fragment_brightness_control_dot_2)
    public boolean onDot2Touched() {
        setRating(2);
        mListener.onRatingChanged(this, 2, true);
        return true;
    }

    @OnTouch(R.id.fragment_brightness_control_dot_3)
    public boolean onDot3Touched() {
        setRating(3);
        mListener.onRatingChanged(this, 3, true);
        return true;
    }

    @OnTouch(R.id.fragment_brightness_control_dot_4)
    public boolean onDot4Touched() {
        setRating(4);
        mListener.onRatingChanged(this, 4, true);
        return true;
    }

    @OnTouch(R.id.fragment_brightness_control_dot_5)
    public boolean onDot5Touched() {
        setRating(5);
        mListener.onRatingChanged(this, 5, true);
        return true;
    }

    @OnTouch(R.id.fragment_brightness_control_dot_6)
    public boolean onDot6Touched() {
        setRating(6);
        mListener.onRatingChanged(this, 6, true);
        return true;
    }

    @OnTouch(R.id.fragment_brightness_control_dot_7)
    public boolean onDot7Touched() {
        setRating(7);
        mListener.onRatingChanged(this, 7, true);
        return true;
    }

    @OnTouch(R.id.fragment_brightness_control_dot_8)
    public boolean onDot8Touched() {
        setRating(8);
        mListener.onRatingChanged(this, 8, true);
        return true;
    }

    @OnTouch(R.id.fragment_brightness_control_dot_9)
    public boolean onDot9Touched() {
        setRating(9);
        mListener.onRatingChanged(this, 9, true);
        return true;
    }

    @OnTouch(R.id.fragment_brightness_control_dot_10)
    public boolean onDot10Touched() {
        setRating(10);
        mListener.onRatingChanged(this, 10, true);
        return true;
    }
    //endregion

    public interface OnRatingBarChangeListener {
        public void onRatingChanged(DotContainerView ratingBar, float value, boolean fromUser);
    }
}
公共类DotContainerView扩展了LinearLayout{
@InjectView(R.id.view\u dot\u容器)
线性布局vDotContainer;
私有的onratingbarchangemlistener;
公共DotContainerView(上下文){
超级(上下文);
初始化();
}
公共DotContainerView(上下文、属性集属性){
超级(上下文,attrs);
初始化();
}
公共DotContainerView(上下文、属性集属性、int-defStyleAttr){
super(上下文、attrs、defStyleAttr);
初始化();
}
@TargetApi(Build.VERSION\u code.LOLLIPOP)
公共DotContainerView(上下文上下文、属性集属性、int-defStyleAttr、int-defStyleRes){
super(context、attrs、defStyleAttr、defStyleRes);
初始化();
}
私有void初始化(){
View root=LayoutInflater.from(getContext()).flate(R.layout.View\u dot\u container,this);
注射(这个,根);
setOnTouchListener(新的OnTouchListener(){
@凌驾
公共布尔onTouch(视图v,运动事件){
v、 事件;
返回false;
}
});
}
公共评级(内部评级){
对于(int index=0;index

这段代码运行良好,如果我点击一个点,前面所有的点都会被选中。唯一的问题是,如果我将手指拖过这些点,它们不会像在
分级栏中那样做出反应,只有在我点击每个点时才会做出反应。你知道怎么解决这个问题吗?。请不要告诉我“使用
分级栏”

我最后做了这样的事情:

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;

import butterknife.ButterKnife;
import butterknife.InjectView;

/**
 * @author astinx
 * @since 0.2
 * <p>
 * Simple widget that shows an array of dots which can be tapped like a {@link android.widget.RatingBar}
 */
public class DotContainerView extends LinearLayout implements View.OnTouchListener {

@InjectView(R.id.view_dot_container)
LinearLayout vDotContainer;

private OnRatingBarChangeListener mListener;

public DotContainerView(Context context) {
    super(context);
    initialize();
}

public DotContainerView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initialize();
}

public DotContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    initialize();
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public DotContainerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    initialize();
}

private void initialize() {
    View root = LayoutInflater.from(getContext()).inflate(R.layout.view_dot_container, this);
    ButterKnife.inject(this, root);
    vDotContainer.setOnTouchListener(this);
}

public void setRating(int rating) {
    //If the rating = 5
    for (int index = 0; index < rating; index++) {
        //This sets the children 10, 9, 8, 5...
        vDotContainer.getChildAt(Math.abs(index - 10) - 1).setSelected(true);
    }
    for (int index = rating; index < 10; index++) {
        //Ant this sets the children 6, 7, 8, 9, 10
        vDotContainer.getChildAt(Math.abs(index - 10) - 1).setSelected(false);
    }
}

public void setOnRatingBarChangeListener(DotContainerView.OnRatingBarChangeListener listener) {
    mListener = listener;
}

@Override
public boolean onTouch(View v, MotionEvent event) {
    float rawX = event.getX();
    float rawY = event.getY();
    setRating(rawX, rawY);
    return true;
}

@Override
public boolean onInterceptHoverEvent(MotionEvent event) {
    float rawX = event.getX();
    float rawY = event.getY();
    setRating(rawX, rawY);
    return super.onInterceptHoverEvent(event);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    float rawX = event.getX();
    float rawY = event.getY();
    setRating(rawX, rawY);
    return false;
}

protected void setRating(float rawX, float rawY) {
    Log.d("DotContainer", "x=" + rawX + ";y=" + rawY);
    int dotIndexByCoords = 10 - findDotIndexByCoords(rawX, rawY);
    setRating(dotIndexByCoords);
    mListener.onRatingChanged(this, dotIndexByCoords, true);
}

private View findViewByIndex(int childIndex) {
    return vDotContainer.getChildAt(childIndex);
}

/**
 * Iterates all over the {@link LinearLayout} searching for the closest child to x,y
 * @param x The x axis
 * @param y The y axis
 * @return The index of the child, -1 if isn't found.
 */
private int findDotIndexByCoords(float x, float y) {
    for (int childIndex = 0; childIndex < vDotContainer.getChildCount(); childIndex++) {
        float y1 = vDotContainer.getChildAt(childIndex).getY();
        float y2 = vDotContainer.getChildAt(childIndex + 1).getY();
        if (y1 <= y && y <= y2) {
            Log.d("DotContainer", "Child no "+ childIndex);
            return childIndex;
        }
    }
    return -1;
}

public interface OnRatingBarChangeListener {
    public void onRatingChanged(DotContainerView ratingBar, float value, boolean fromUser);
}
  }
导入android.annotation.TargetApi;
导入android.content.Context;
导入android.os.Build;
导入android.util.AttributeSet;
导入android.util.Log;
导入android.view.LayoutInflater;
导入android.view.MotionEvent;
导入android.view.view;
导入android.widget.LinearLayout;
进口毛刀,毛刀;
导入butterknife.InjectView;
/**
*@author astinx
*@自0.2
*
*一个简单的小部件,显示一组点,可以像{@link android.widget.RatingBar}一样点击
*/
公共类DotContainerView扩展了LinearLayout实现了View.OnTouchListener{
@InjectView(R.id.view\u dot\u容器)
线性布局vDotContainer;
私有的onratingbarchangemlistener;
公共DotContainerView(上下文){
超级(上下文);
初始化();
}
公共DotContainerView(上下文、属性集属性){
超级(上下文,attrs);
初始化();
}
公共DotContainerView(上下文、属性集属性、int-defStyleAttr){
super(上下文、attrs、defStyleAttr);
初始化();
}
@TargetApi(Build.VERSION\u code.LOLLIPOP)
公共DotContainerView(上下文上下文、属性集属性、int-defStyleAttr、int-defStyleRes){
super(context、attrs、defStyleAttr、defStyleRes);
初始化();
}
私有void初始化(){
视图根=LayoutFlater.from(getContext())。充气(R