绘制圆形抽奖转盘

最近要做一个抽奖活动因为比较空闲所以花时间看了一下,哈哈,下面记录一下

绘制文字:主要求出圆弧长度,再计算出文字长度,(圆弧长-文字长)/2=文字离两边的距离(文字居中处理)

还用到了在线图片的下载和保存以及展示

支持滑动到指定的位置

上传gif老是失败,先看看图片

上代码

package cn.wangxiao.crm.myprizedemo;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewCompat;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;

import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.assist.ImageSize;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.UUID;

/**
 * Created by ytt on 2018/3/2.
 */

public class MyPrizeView extends View {
    private static final String IN_PATH = "/Android/pic/";
    private List<MyPrizeBean> myPrizeList;
    /**
     * 当前控件的宽高
     */
    private int minWidthAndHeight;
    /**
     * 当前控件的半径
     */
    private int radius;
    /**
     * 写字和画圆弧的画笔
     */
    Paint mTextPaint;
    Paint mBgPaint;

    /**
     * 当前角度
     */
    int initAngle = 0;
    /**
     * 每一个奖品占的角度,例如 六个奖品,sweepAngle=360/6
     */
    int sweepAngle;

    private Canvas mCanvas;

    public MyPrizeView(Context context) {
        this(context, null);
    }

    public MyPrizeView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyPrizeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView() {
        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        Log.i("ytt", "MyPrizeView: onSizeChanged");
        //获取宽高
        minWidthAndHeight = Math.min(w, h);
        radius = minWidthAndHeight / 2;

    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mCanvas = canvas;
        if (myPrizeList != null && myPrizeList.size() > 0) {
            mTextPaint.setTextSize(radius / 10);
            //每一个奖品占有的角度
            sweepAngle = 360 / myPrizeList.size();
            for (int i = 0; i < myPrizeList.size(); i++) {
                RectF rectF = new RectF(0, 0, minWidthAndHeight, minWidthAndHeight);
                if (i % 2 == 0) {
                    mTextPaint.setColor(Color.rgb(255, 133, 132));
                } else {
                    mTextPaint.setColor(Color.rgb(254, 104, 105));
                }
                //绘制圆弧
                canvas.drawArc(rectF, initAngle, sweepAngle, true, mTextPaint);

                //绘制文字
                mTextPaint.setColor(Color.WHITE);
                drawCurrentText(rectF, initAngle, sweepAngle, myPrizeList.get(i).text, canvas);
                //绘制图片
                if (!TextUtils.isEmpty(myPrizeList.get(i).address)) {
                    if (myPrizeList.get(i).myBitmap != null) {
                        drawCurrentPicture(initAngle, myPrizeList.get(i).myBitmap);
                    } else {
                        myPrizeList.get(i).myBitmap = BitmapFactory.decodeFile(myPrizeList.get(i).address);
                        drawCurrentPicture(initAngle, myPrizeList.get(i).myBitmap);
                        Log.i("ytt", "地址:" + myPrizeList.get(i).address);
                    }
                } else {
                    //加载网络图片
                    loadingPicture(i, myPrizeList.get(i).icon);
                }
                initAngle += sweepAngle;
            }
        }
        initAngle = initAngle % 360;
    }

    /**
     * 绘制文字
     */
    private void drawCurrentText(RectF rectF, int angle, int sweepAngle, String text, Canvas canvas) {
        Path path = new Path();
        path.addArc(rectF, angle, sweepAngle);
        float textWidth = mTextPaint.measureText(text);
        Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
        //圆弧的水平偏移 先计算出弧长 减去文字长度/2的长度就是距离两边的距离
        float hOffset = (float) (2*Math.PI*radius * sweepAngle/360-textWidth)/2;
        //圆弧的垂直偏移,文字的高度
        float vOffset = Math.abs(fontMetrics.top - fontMetrics.bottom);
        canvas.drawTextOnPath(text, path, hOffset, vOffset, mTextPaint);
    }

    /**
     * 绘制图片
     */
    private void drawCurrentPicture(int startAngle, Bitmap myBitmap) {
        // 设置图片的宽度
        int imgWidth = minWidthAndHeight / (myPrizeList.size() <= 3 ? myPrizeList.size() + 2 : myPrizeList.size());

        float angle = (float) ((360 / myPrizeList.size() / 2 + startAngle) * (Math.PI / 180));

        int x = (int) (radius + minWidthAndHeight / 2 / 2 * Math.cos(angle));
        int y = (int) (radius + minWidthAndHeight / 2 / 2 * Math.sin(angle));

        int addInt = imgWidth / 2;

        RectF rect = new RectF(x - addInt, y - addInt, x + addInt, y + addInt);

        if (myBitmap != null && !myBitmap.isRecycled()) {
            mCanvas.drawBitmap(myBitmap, null, rect, null);
        }
    }

    /***
     * 加载网络图片
     * */
    private void loadingPicture(final int position, final String address) {
        if (TextUtils.isEmpty(address)) {
            return;
        }
        /**
         * 设置ImageSize和DisplayImageOptions避免图片太大,占用内存太多
         * */
        ImageLoader.getInstance().loadImage(address, new ImageSize(50, 50), DisplayImageOptions.createSimple(), new SimpleImageLoadingListener() {
            @Override
            public void onLoadingCancelled(String imageUri, View view) {
                super.onLoadingCancelled(imageUri, view);
                Log.i("ytt", "图片加载onLoadingCancelled  " + position);
            }

            @Override
            public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                super.onLoadingComplete(imageUri, view, loadedImage);
                Log.i("ytt", "图片加载完成onLoadingComplete " + position);
                if (myPrizeList != null && myPrizeList.size() > position) {
                    myPrizeList.get(position).address = saveBitmap(loadedImage);
                    ViewCompat.postInvalidateOnAnimation(MyPrizeView.this);
                }
            }

            @Override
            public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
                super.onLoadingFailed(imageUri, view, failReason);
                Log.i("ytt", "图片加载onLoadingFailed " + position);
            }

        });
    }

    /**
     * 随机生产文件名
     *
     * @return
     */
    private static String generateFileName() {
        return UUID.randomUUID().toString();
    }

    /**
     * 保存bitmap到本地
     *
     * @param
     * @param mBitmap
     * @return
     */
    public String saveBitmap(Bitmap mBitmap) {
        String savePath;
        File filePic;
        savePath = getContext().getApplicationContext().getFilesDir().getAbsolutePath() + IN_PATH;
        try {
            filePic = new File(savePath + generateFileName() + ".jpg");
            if (!filePic.exists()) {
                filePic.getParentFile().mkdirs();
                filePic.createNewFile();
            }
            FileOutputStream fos = new FileOutputStream(filePic);
            mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
            fos.flush();
            fos.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }

        return filePic.getAbsolutePath();
    }

    public void setListData(List<MyPrizeBean> myPrizeList) {
        this.myPrizeList = myPrizeList;
        invalidate();
    }
    /**
     * 开始转动
     */
    public void startRotate(int position) {
        //算出未转动时的角度
        int currentAngle = 360 - (position - 1) * sweepAngle + 270 - sweepAngle / 2 + 360 * 2;
        ValueAnimator animtor = ValueAnimator.ofInt(initAngle % 360, currentAngle + initAngle / 360 * 360);
        animtor.setInterpolator(new AccelerateDecelerateInterpolator());
        animtor.setDuration(2500);
        animtor.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int updateValue = (int) animation.getAnimatedValue();
                initAngle = (updateValue % 360 + 360) % 360;
                ViewCompat.postInvalidateOnAnimation(MyPrizeView.this);
            }
        });
        animtor.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
            }
        });
        animtor.start();
    }

}
主要的实现类


xml中的写法

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="cn.wangxiao.crm.myprizedemo.MainActivity">

    <cn.wangxiao.crm.myprizedemo.MyPrizeView
        android:id="@+id/myPrizeView"
        android:layout_width="match_parent"
        android:layout_marginTop="20dp"
        android:layout_height="match_parent"
        android:text="Hello World!"
        tools:layout_editor_absoluteX="8dp"
        tools:layout_editor_absoluteY="8dp" />

    <EditText
        android:id="@+id/edittext"
        android:layout_width="match_parent"
        android:layout_alignParentBottom="true"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/xixi"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="30dp"
        android:text="开始" />

</RelativeLayout>

主要调用类

package cn.wangxiao.crm.myprizedemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.EditText;

import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private MyPrizeView myPrizeView;
    private String[] string = new String[]{"https://cdn.duitang.com/uploads/item/201506/29/20150629091228_aF2WC.jpeg", "http://pic13.nipic.com/20110421/7074946_131907700142_2.jpg",
            "http://pic.58pic.com/58pic/15/39/80/91k58PICXEU_1024.jpg", "http://scimg.jb51.net/allimg/160706/103-160F6095531355.jpg", "http://pic23.photophoto.cn/20120624/0010023982061468_b.jpg"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ImageLoader imageLoader = ImageLoader.getInstance();
        imageLoader.init(ImageLoaderConfiguration.createDefault(this));
        myPrizeView = (MyPrizeView) findViewById(R.id.myPrizeView);

        final EditText editText = (EditText) findViewById(R.id.edittext);


        findViewById(R.id.xixi).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // myPrizeView.startRotate(1);
                setNumber(Integer.parseInt(editText.getText().toString().trim()) );
            }
        });
    }

    public void setNumber(int number) {
        List<MyPrizeBean> myPrizeBeanList = new ArrayList<>();
        for (int i = 0; i < number; i++) {
            MyPrizeBean bean = new MyPrizeBean();
            bean.text = "" + (i + 1);
            bean.icon = string[i % string.length];
            myPrizeBeanList.add(bean);
        }
        myPrizeView.setListData(myPrizeBeanList);

        myPrizeView.startRotate(number);
    }
}

好了好了,不玩了,就是这样的,三个类就可以跑


有用到imageLoade

在app/build.gradle中添加

compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'

需要在项目入口初始化

 ImageLoader imageLoader = ImageLoader.getInstance();
 imageLoader.init(ImageLoaderConfiguration.createDefault(this));

就可以跑啦


项目地址: https://github.com/ytttp/MyPrizeDemo

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值