欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android自定义View实现拼手气转盘

程序员文章站 2023-01-29 11:57:55
效果图 原理分析 这里的转盘主要实现的重点是绘制每块答案区域的文本,并绘制出来,而转盘和背景只是张图片 1、绘制文本的位置区域 2、获取旋转动画 3、提供接口 实现步骤 1、初始化变量 //文...

效果图

Android自定义View实现拼手气转盘

原理分析

这里的转盘主要实现的重点是绘制每块答案区域的文本,并绘制出来,而转盘和背景只是张图片

1、绘制文本的位置区域
2、获取旋转动画
3、提供接口

实现步骤

1、初始化变量

//文本相关
private list mrollgametextlist;
private int mrollgametextcount = 0;
private paint mtextpaint;
private int mtextsize = 14;

private rectf mrange; //view的区域
private int mradius; //view的直径
private int mwidth; //view的宽度
private float mstartangle = 22.5f; //开始的角度

//旋转动画相关
private boolean isrolling = false;
private float fromdegress = 0;
private float todegress = 0;
//拼手气的正确答案位置
private int manswerposition = 0;
//拼手气转盘转一圈的时间
private int mtimeforper = 800;
//拼手气转盘的圈数
private int mrollcount = 3;
//拼手气转盘第一行文本的个数
private int mfirstlinetextcount = 4;

2、测量大小

public rollgametextviewlist(context context) {
   this(context, null);
}

public rollgametextviewlist(context context, @nullable attributeset attrs) {
    this(context, attrs, 0);
}

public rollgametextviewlist(context context, @nullable attributeset attrs, int defstyleattr) {
    super(context, attrs, defstyleattr);

    mtextpaint = new paint();
    mtextpaint.setcolor(color.parsecolor("#611e14"));
    mtextpaint.settextsize(dip2px(context, mtextsize));
}

/**
 * 设置为正方形
 *
 * @param widthmeasurespec
 * @param heightmeasurespec
 */
@override
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
    super.onmeasure(widthmeasurespec, heightmeasurespec);

    mwidth = math.min(getmeasuredwidth(), getmeasuredheight());
    mradius = mwidth - getpaddingleft() - getpaddingright();
    setmeasureddimension(mwidth, mwidth);
    mrange = new rectf(getpaddingleft(), getpaddingtop(), mradius
            + getpaddingleft(), mradius + getpaddingtop());
}

3、绘制文本

@override
protected void ondraw(canvas canvas) {
    if (checkstartcondition()) {
        canvas.save();
        canvas.rotate(-90, mwidth / 2, mwidth / 2);

        float tmpangle = mstartangle;
        float sweepangle = (float) (360 / mrollgametextcount);

        for (int i = 0; i < mrollgametextlist.size(); i++) {
            drawtext(canvas, tmpangle, sweepangle, mrollgametextlist.get(i), i);
            tmpangle += sweepangle;
        }
        canvas.restore();
    }
}

private void drawtext(canvas canvas, float startangle, float sweepangle, string text, int position) {
    if (text.length() >= mfirstlinetextcount) {
        drawlinetwo(canvas, startangle, sweepangle, text, position);
    } else {
        drawlineone(canvas, startangle, sweepangle, text, position);
    }
}

/**
 * 兼容两行文本
 *
 * @param canvas
 * @param startangle
 * @param sweepangle
 * @param text
 */
private void drawlinetwo(canvas canvas, float startangle, float sweepangle, string text, int position) {
    string textforward = text.substring(0, mfirstlinetextcount);
    string textforback = text.substring(mfirstlinetextcount, text.length());

    int textwidthforward = measuretextview(textforward).width();
    int textheightforward = measuretextview(textforward).height();
    int textwidthforback = measuretextview(textforback).width();
    int textheightforback = measuretextview(textforback).height();

    float h1_offset = (float) (mradius * math.pi / mrollgametextcount / 2 - textwidthforward / 2);// 水平偏移:圆长/个数/2 - 文本宽度/2
    float v1_offset = textheightforward;// 垂直偏移
    float h2_offset = (float) (mradius * math.pi / mrollgametextcount / 2 - textwidthforback / 2);// 水平偏移:圆长/个数/2 - 文本宽度/2
    float v2_offset = textheightforward + textheightforback;// 垂直偏移

    path path = new path();
    path.addarc(mrange, startangle, sweepangle);
    canvas.drawtextonpath(textforward, path, h1_offset, v1_offset, mtextpaint);
    canvas.drawtextonpath(textforback, path, h2_offset, v2_offset, mtextpaint);
}

/**
 * 兼容一行文本
 *
 * @param canvas
 * @param startangle
 * @param sweepangle
 * @param text
 */
private void drawlineone(canvas canvas, float startangle, float sweepangle, string text, int position) {
    path path = new path();
    path.addarc(mrange, startangle, sweepangle);
    int textwidth = measuretextview(text).width();
    int textheight = measuretextview(text).height();
    float hoffset = (float) (mradius * math.pi / mrollgametextcount / 2 - textwidth / 2);// 水平偏移:圆长/个数/2 - 文本宽度/2
    float voffset = textheight;// 垂直偏移
    canvas.drawtextonpath(text, path, hoffset, voffset, mtextpaint);
}

/**
 * 测量文本
 *
 * @param text
 * @return
 */
private rect measuretextview(string text) {
    rect bounds = new rect();
    mtextpaint.gettextbounds(text, 0, text.length(), bounds);
    return bounds;
}

4、旋转动画

 /**
 * 开启拼手气
 */
private void startrollgame() {
    if (checkstartcondition()) {
        if (!isrolling) {
            isrolling = true;
            todegress = manswerposition * 45 + mrollcount * 360;
            startrollgamerotateanimation(fromdegress, todegress);
            fromdegress = fromdegress + (todegress - fromdegress) % 360;

            log.e("tag", "fromdegress:" + fromdegress + "-todegress:" + todegress + "-" + manswerposition);
        }
    }
}

/**
 * 判断开启条件
 *
 * @return
 */
private boolean checkstartcondition() {
    if (null == mrollgametextlist || mrollgametextlist.size() == 0 || mrollcount == 0) {
        return false;
    }
    return true;
}

/**
 * 开启旋转动画
 *
 * @param fromdegress
 * @param todegress
 */
private void startrollgamerotateanimation(float fromdegress, float todegress) {
    rotateanimation rollgamerotateanimation = getrollgamerotateanimation(fromdegress, todegress);
    startanimation(rollgamerotateanimation);
}

/**
 * 获取旋转动画
 *
 * @param fromdegress
 * @param todegress
 * @return
 */
private rotateanimation getrollgamerotateanimation(float fromdegress, float todegress) {
    rotateanimation rotateanimation = new rotateanimation(fromdegress, todegress, mwidth / 2, mwidth / 2);
    rotateanimation.setinterpolator(new acceleratedecelerateinterpolator());
    rotateanimation.setduration((long) ((todegress - fromdegress) / 360 * mtimeforper));
    rotateanimation.setanimationlistener(rollgameanimlistener);
    rotateanimation.setfillafter(true);
    return rotateanimation;
}

/**
 * 动画监听
 */
private animation.animationlistener rollgameanimlistener = new animation.animationlistener() {
    @override
    public void onanimationstart(animation animation) {

    }

    @override
    public void onanimationend(animation animation) {
        isrolling = false;
    }

    @override
    public void onanimationrepeat(animation animation) {

    }
};

5、提供api

public void setanswerposition(int manswerposition) {
    this.manswerposition = manswerposition;
}

public void settimeforper(int mtimeforper) {
    this.mtimeforper = mtimeforper;
}

public void setrollcount(int mrollcount) {
    this.mrollcount = mrollcount;
}

public void setfirstlinetextcount(int mfirstlinetextcount) {
    this.mfirstlinetextcount = mfirstlinetextcount;
}

public void setrollgametextlist(list mrollgametextlist) {
    if (null != mrollgametextlist && mrollgametextlist.size() > 0) {
        this.mrollgametextlist = mrollgametextlist;
        this.mrollgametextcount = mrollgametextlist.size();
        collections.reverse(mrollgametextlist);
        invalidate();
    }
}

/**
 * 开启动画
 */
public void start() {
    startrollgame();
}

6、转盘的使用

public class mainactivity extends appcompatactivity{

    private rollgametextviewlist iv_rollgame_context;
    private static list text = new arraylist<>();

    static {
        text.add("送");
        text.add("送礼");
        text.add("送礼物");
        text.add("送礼物吧");
        text.add("送礼物微信");
        text.add("送礼物我爱你");
        text.add("送礼物宝贵砖石");
        text.add("送礼物我爱你么么");
    }

    @override
    protected void oncreate(bundle savedinstancestate) {
        super.oncreate(savedinstancestate);
        setcontentview(r.layout.activity_main);

        iv_rollgame_context = findviewbyid(r.id.iv_rollgame_context);
        iv_rollgame_context.setrollcount(10);
        iv_rollgame_context.settimeforper(800);
        iv_rollgame_context.setanswerposition(2);
        iv_rollgame_context.setfirstlinetextcount(4);
        iv_rollgame_context.setrollgametextlist(text);
    }

    public void startroll(view view) {
        iv_rollgame_context.start();
    }
}

其布局的实现




    

    

效果如下

Android自定义View实现拼手气转盘