Android转盘设计思路,Android 大转盘

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

// 外部调用方法

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;

/**

*

 
 

* (v1 + 0) * (v1+1) / 2 = target ;

* v1*v1 + v1 - 2target = 0 ;

* v1=-1+(1*1 + 8 *1 * target)/2;

*

*/

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);

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值