美文网首页
Android 大转盘

Android 大转盘

作者: Marlon666 | 来源:发表于2018-10-26 16:19 被阅读14次

商品角度朝中心位置偏转。

 // 外部调用方法   
private void getImg(String logoURL) {
    ImageView imageView1 = new ImageView(this);
    ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(214, 308);
    imageView1.setLayoutParams(params);
    Picasso.with(this).load(logoURL).into(imageView1);
    mLuckyPanView.setChildView(imageView1);
}



public class TurntableView extends ViewGroup {

InterfaceBackToast interfaceBackToast = null;

/**
 * 自定义控件的自定义事件
 * @para m iBack 接口类型
 */
public void setonClick(InterfaceBackToast iBack) {
    interfaceBackToast = iBack;
}

public void onDestory() {

}

public interface InterfaceBackToast {
    public void oninterfaceback();
}

/**
 * 1.绘制背景圆圈
 * 2.添加 addImageView 形成一个圈。
 */
private int mWidth;  //ViewGroup 宽度
private PointF mCenterPoint;
private int LayoutRadius; //直径
private int childCount = 0;
private volatile float mStartAngle = 270;

/**
 * 滚动的速度
 */
private float mSpeed = 0;

/**
 * 是否滑动
 */

private boolean isFling = false;
/**
 * 绘制盘快的画笔
 */
private Paint mArcPaint;

/**
 * 绘制盘块的范围
 */
private RectF mRange = new RectF();

public TurntableView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    Log.d("onlayout", "onlayout 进来");
    if(!isFling){
        if (getChildCount() != 0){
            mStartAngle = 270 - 360 / getChildCount() /2;
        }
    }
    setChildLayout(l, t, r, b);
}

private void init() {
    mCenterPoint = new PointF();
    mArcPaint = new Paint();
    mArcPaint.setAntiAlias(true);
    mArcPaint.setDither(true);
    //调用这句话,要不然不能绘制onDraw方法
    setWillNotDraw(false);
}

//父类控件的可用大小
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    mWidth = measureHanlder(widthMeasureSpec);
    int width = mWidth;

    /**
     * 宽和高  选择其中一个最小的来设置  view宽高
     */
    mCenterPoint.x = mWidth / 2;
    mCenterPoint.y = mWidth / 2;

    LayoutRadius = width - getPaddingLeft() - getPaddingRight();
    mRange = new RectF(getPaddingLeft(), getPaddingLeft(), LayoutRadius + getPaddingLeft()
            , LayoutRadius + getPaddingLeft());

    /**
     *  测绘子view的大小
     */
    for (int i = 0; i < getChildCount(); i++) {
        View view = getChildAt(i);
        measureChild(view, MeasureSpec.makeMeasureSpec(100, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(100, MeasureSpec.AT_MOST));
    }
    setMeasuredDimension(width, width);
    Log.d("onDraw", "onMeasure");
}


@Override
protected void onDraw(Canvas canvas) {
    Log.d("onDraw", "onDraw");
    float tmpAngle = mStartAngle;
    float sweepAngle;
    if (childCount != 0) {
        sweepAngle = 360 / childCount;
    } else {
        //当什么奖品没有的时候,设置的颜色。
        sweepAngle = 360;
        mArcPaint.setColor(Color.argb(0, 0, 0, 0));
        canvas.drawArc(mRange, tmpAngle, sweepAngle, true, mArcPaint);
    }

    /**
     * 绘制转盘的背景
     */
    for (int i = 0; i < childCount; i++) {
        if (i % 2 == 0) {
            mArcPaint.setColor(Color.rgb(254, 227, 76));
        } else {
            mArcPaint.setColor(Color.rgb(1, 136, 200));
        }
        canvas.drawArc(mRange, tmpAngle, sweepAngle, true, mArcPaint);
        tmpAngle += sweepAngle;
    }

    if (isFling) {
        setChildLayout(0, 0, 0, 0);
    }
}


//设置view的位置
private void setChildLayout(int l, int t, int r, int b) {
    childCount = getChildCount();
    if (childCount == 0) return;
    float childAngle = (float) (360 / childCount);

    Log.d("childAngle", "childAngle=" + childAngle);
    float tmpAngle = mStartAngle;
    for (int i = 0; i < childCount; i++) {
        //开始绘制自布局的时候,就已经得到该布局的大小了
        View view = getChildAt(i);
        int childHeight = view.getMeasuredHeight();
        int childWidth = view.getMeasuredWidth();
        //  Log.d("onlayout", "childHeight=" + childHeight + "  childWidth=" + childWidth);
        drawIcon(tmpAngle, view, childWidth, childHeight, i);
        Log.d("tmpAngle", "tmpAngle=" + tmpAngle + " i=" + (i + 1));
        tmpAngle += childAngle;
    }

}


/**
 * android  30° 是顺时针方向.
 *
 * @param startAngle 起始角度
 */
public void drawIcon(float startAngle, View view, int width, int height, int i) {
    /**
     *   每个View 角度 α/2
     */
    float ItemCenterPoint = (360 / childCount / 2);

    float angle = (float) ((ItemCenterPoint + startAngle) * (Math.PI / 180));

    /**
     *   解释一下:
     *   (0,0)  当count=4时候
     *   第一个角度是0°。 但是我们需要偏移到自己象限的中间。
     *   0°+itemCenterPoint   itemCenterPoint等于=45° 记住是顺时针旋转。
     *
     *   ---------------
     *  | \
     *  |  \
     *  |   \
     *
     * 为什么ImageView 选择角度是这样算的。这里主要说明90°的原因
     *
     *   *
     *   *  View 指向上
     *   *
     *   * * * * *
     *    *  这个角度是我们View偏移的角度,但是我们View是向上的 需要多加一个90° 让它回归到 水平位置
     *     *
     *      *
     */
    float n = startAngle % 360 + ItemCenterPoint + 90;
    Log.d("n-drawIcon", "startAngle%360=" + (startAngle % 360) + " ItemCenterPoint=" + ItemCenterPoint + " n=" + n + " startAngle=" + startAngle);
    int x = (int) (mCenterPoint.x + (LayoutRadius / 3) * Math.cos(angle));
    int y = (int) (mCenterPoint.y + (LayoutRadius / 3) * Math.sin(angle));
    Log.d("drawIcon", "postion=" + " angle=" + angle + " x=" + x + " y=" + y);
    view.layout(x - width / 2, y - width / 2, x + width / 2, y + width / 2);
    setViewAngle(n, view);
}


/**
 * 根据角度来设置View角度
 */
public void setViewAngle(float mStartAngle, View view) {
    Log.d("setViewAngle", "setViewAngle=" + mStartAngle);
    view.setRotation(mStartAngle);
}


private int measureHanlder(int measureSpec) {
    int result;
    //获得当前view 的显示模式
    int specMode = MeasureSpec.getMode(measureSpec);

    //获得当前view 的大小
    int specSize = MeasureSpec.getSize(measureSpec);

    //如果为测量时的大小
    if (specMode == MeasureSpec.EXACTLY) {
        result = specSize;
    } else if (specMode == MeasureSpec.AT_MOST) {
        result = Math.min(100, specSize);
    } else {
        result = 100;
    }
    return result;
}


public void setChildView(View view) {
    addView(view);
}

/**
 * 点击开始旋转
 * @param luckyIndex
 */
public void luckyStart(int luckyIndex) {
    // 每项角度大小
    float angle = (float) (360 / getChildCount());
    // 中奖角度范围(因为指针向上,所以水平第一项旋转到指针指向,需要旋转210-270;)
    float from = 270 - (luckyIndex + 1) * angle +  angle/2;
    float to = from + angle ;
    // 停下来时旋转的距离
    float targetFrom = 4 * 360 + from;
    /**
     * <pre>
     *  (v1 + 0) * (v1+1) / 2 = target ;
     *  v1*v1 + v1 - 2target = 0 ;
     *  v1=-1+(1*1 + 8 *1 * target)/2;
     * </pre>
     */
    float v1 = (float) (Math.sqrt(1 * 1 + 8 * 1 * targetFrom) - 1) / 2;
    float targetTo = 4 * 360 + to;
    float v2 = (float) (Math.sqrt(1 * 1 + 8 * 1 * targetTo) - 1) / 2;
    mSpeed = v1;
    isFling = true;
    mStartAngle = 0;
    post(mFlingRunnable = new AutoFlingRunnable(mSpeed));
}

public boolean isFling() {
    return isFling;
}

public void setFling(boolean fling) {
    isFling = fling;
}

/**
 * 自动滚动的Runnable
 */
private AutoFlingRunnable mFlingRunnable;


/**
 * 自动滚动的任务
 */
private class AutoFlingRunnable implements Runnable {

    private float angelPerSecond;

    public AutoFlingRunnable(float velocity) {
        this.angelPerSecond = velocity;
    }

    public void run() {
        if ((int) Math.abs(angelPerSecond) <= 0) {
            isFling = false;
            mSpeed = 0;
            interfaceBackToast.oninterfaceback();
            return;
        }
        isFling = true;

        mStartAngle += angelPerSecond;

        // 逐渐减小这个值
        angelPerSecond --;
        // 重新布局
        invalidate();
        //50 毫秒之后再次开启这个线程
        postDelayed(this, 50);
    }
}

@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
    switch (e.getAction()) {
        case MotionEvent.ACTION_DOWN:
            break;
        case MotionEvent.ACTION_MOVE:
            //必须要在MOVE中return才有效果,在这里return后UP事件也会被拦截
            return true;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            break;
    }
    return super.onInterceptTouchEvent(e);
}

相关文章

  • Android 大转盘

    商品角度朝中心位置偏转。

  • Android实现幸运大转盘功能

    参考: 功能概述: 旋转之后根据随机数来影响最后指针停留的位置,也就是旋转的角度。有两种转法,指针转和转盘转,这里...

  • 【one week one project】大转盘转啊转

    【one week one project】大转盘转啊转 访问地址:大转盘GitHub:Github 项目背景: ...

  • Android 自定义View 抽奖大转盘(2)

    这是转盘的第二个版本,添加了外围的圆圈 第一个demo在这儿可以找到 Android 自定义View 抽奖大转盘(...

  • GAME

    一、大转盘1、获取用户大转盘可用次数url: /applet_necessary_game/getTurnPlat...

  • 魔众大转盘抽奖系统 v2.0.0 全面升级 系统更好用

    魔众大转盘抽奖系统是一个可快速私有化的大转盘系统,可以创建多个大转盘活动,奖品支持现金红包、积分、实物礼品、兑换码...

  • 哈哈,双喜临门

    大转盘真是快乐发生器~ 今早转大转盘,先转了个1万卡,小开心一下,也没想着截图。 估计大转盘觉得我太没把它当回事,...

  • Android 自定义View 抽奖大转盘(3[完])

    在这里将头两篇做了一个整合,两个自定义View变成了一个自定义View Android 自定义View 抽奖大转盘...

  • 抽奖

    今天早晨,打开简书,发现抽奖的大转盘没有了,不禁轻轻松了口气。 最近, 发现简书有个大转盘之后,几...

  • php实现刮刮卡大转盘抽奖概率

    php实现刮刮卡大转盘抽奖概率 本文实例为大家分享了php中奖概率算法,可用于刮刮卡,大转盘等抽奖算法,用法很简单...

网友评论

      本文标题:Android 大转盘

      本文链接:https://www.haomeiwen.com/subject/lzcltqtx.html