美文网首页
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 大转盘

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