Android自定义View实现QQ运动积分转盘抽奖功能

因为偶尔关注QQ运动, 看到QQ运动的积分抽奖界面比较有意思,所以就尝试用自定义View实现了下,原本想通过开发者选项查看下界面的一些信息,后来发现积分抽奖界面是在WebView中展示的,应该是在H5页面中用js代码实现的,暂时不去管它了。

  这里的自定义View针对的是继承自View的情况,你可以将Canvas想象为画板, Paint为画笔,自定义View的过程和在画板上用画笔作画其实类似,想象在画板上作画的过程,你要画一个多大图形(对应View的测量 onMeasure方法),你要画什么样的图形,比如圆形方形等等(对应View的onDraw方法),在掌握了View的一些基础概念(位置参数、触摸事件、滑动),测量模式、事件分发机制、绘制流程等知识后,自定义View的时候就不觉得复杂了。

  不管是多么复杂的View,其内部基本都可以拆分至一个个小单元,比如如下的QQ运动积分抽奖画面,(QQ --> 动态 --> 运动 --> 我 --> 积分)

  这里我们只关注抽奖的转盘,因为是截图没有动画效果,具体可以在自己的手机上查看下。这个抽奖的界面看似复杂,其实可以分为几个部分

  1. 最外层圆环,其中有小圆圈闪动

  2, 内部圆角矩形

  3.  内部圆角卡片(包含一个图片或说明文字)

第一步:我们要继承View类, 如果需要自定义属性则应该实现带三个参数的构造方法,这里将自定义View命名为 LotteryView

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

  public LotteryView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }

  public LotteryView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context, attrs);
  }

  在init方法中可以做一些初始化的操作,比如需要用的颜色值,画笔Paint, 宽高信息等,如果有自定义属性,也可以在init方法中处理。

  接着可以设定View的宽高信息,这里我们将View设置为正方形  

 @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    setMeasuredDimension(mSelfTotalWidth, mSelfTotalWidth);
  }

  调用setMeasureDimension方法,宽高都设置为 mSelfTotalWidth。这里我们宽高是限定的值,所以不需要的处理不同测量模式的情况,如果是其他自定义View要支持wrap_content属性,需要在onMeasure方法中自行处理

第一步:绘制外层带圆角的圆环

/** 外层带圆角矩形圆环 */
  private void drawOuterRoundCircle(Canvas canvas) {
    canvas.save();
    canvas.clipRect(
        mOuterCircleWidth + getPaddingLeft(),
        mOuterCircleWidth + getPaddingTop(),
        mSelfTotalWidth - mOuterCircleWidth - getPaddingRight(),
        mSelfTotalWidth - mOuterCircleWidth - getPaddingBottom(),
        Region.Op.DIFFERENCE);

    canvas.drawRoundRect(
        getPaddingLeft(),
        getPaddingTop(),
        mSelfTotalWidth - getPaddingRight(),
        mSelfTotalWidth - getPaddingBottom(),
        18, 18, mOuterCirclePaint);
    canvas.restore();
  }

绘制外层圆环中的小圆圈

private void drawOuterDecorateSmallCircle(Canvas canvas) {
    int result = mInvalidateCircleCount % 2;

    // top
    int x = 0, y = 0;
    int sideSize = mSelfTotalWidth - mOuterCircleWidth * 2 - getPaddingLeft() - getPaddingRight(); // 除去最外边圆环后的边长
    for (int i = 0; i < 10; i++) {
      mSmallCirclePaint.setColor(i % 2 == result ? mSmallCircleYellowColor : mSmallCircleBlueColor);
      x = mOuterCircleWidth + (sideSize - mSmallCircleRadius * 2 * 9) / 9 * i + mSmallCircleRadius * 2 * i + getPaddingLeft();
      y = (mOuterCircleWidth - mSmallCircleRadius * 2) / 2 + mSmallCircleRadius + getPaddingTop();
      canvas.drawCircle(x, y, mSmallCircleRadius, mSmallCirclePaint);
    }

    // bottom
    for (int i = 0; i < 10; i++) {
      mSmallCirclePaint.setColor(i % 2 == result ? mSmallCircleYellowColor : mSmallCircleBlueColor);
      x = mOuterCircleWidth + (sideSize - mSmallCircleRadius * 2 * 9) / 9 * i + mSmallCircleRadius * 2 * i + getPaddingLeft();
      y = mSelfTotalWidth - mOuterCircleWidth + (mOuterCircleWidth - mSmallCircleRadius * 2) / 2 + mSmallCircleRadius - getPaddingBottom();
      canvas.drawCircle(x, y, mSmallCircleRadius, mSmallCirclePaint);
    }

    // left
    for(int i = 0; i < 9; i++) {
      mSmallCirclePaint.setColor(i % 2 == (result == 0 ? 1 : 0) ? mSmallCircleYellowColor : mSmallCircleBlueColor);
      x = mOuterCircleWidth / 2 + getPaddingLeft();
      y = mOuterCircleWidth*2 + (sideSize - mSmallCircleRadius * 2 * 9) / 9 * i + mSmallCircleRadius * 2 * i + getPaddingTop();
      canvas.drawCircle(x, y, mSmallCircleRadius, mSmallCirclePaint);
    }

    // right
    for(int i = 0; i < 9; i++) {
      mSmallCirclePaint.setColor(i % 2 == result ? mSmallCircleYellowColor : mSmallCircleBlueColor);
      x = mSelfTotalWidth - mOuterCircleWidth / 2 - getPaddingRight();
      y = mOuterCircleWidth*2 + (sideSize - mSmallCircleRadius * 2 * 9) / 9 * i + mSmallCircleRadius * 2 * i + getPaddingTop();
      canvas.drawCircle(x, y, mSmallCircleRadius, mSmallCirclePaint);
    }
  }

第二步:绘制内部的圆角矩形,即卡片所在区域的背景

private void drawInnerBackground(Canvas canvas) {
    canvas.drawRect(mOuterCircleWidth + getPaddingLeft(), mOuterCircleWidth + getPaddingTop(),
        mSelfTotalWidth - mOuterCircleWidth - getPaddingRight(),
        mSelfTotalWidth - mOuterCircleWidth - getPaddingBottom(), mInnerPaint);
  }

第三步: 绘制内部小卡片

private void drawInnerCards(Canvas canvas) {
    int left = 0, top = 0, right = 0, bottom = 0;
    int spaceNum = 0;
    for(int i = 0 ; i < 9 ; i++) {
      spaceNum = i % 3 + 1;
      left = mOuterCircleWidth + mInnerCardWidth * (i%3) + mInnerCardSpace * spaceNum + getPaddingLeft();
      top = mOuterCircleWidth + mInnerCardWidth * (i/3) +mInnerCardSpace * (i/3 + 1) + getPaddingTop();
      right = left + mInnerCardWidth;
      bottom = top + mInnerCardWidth;
      if(!mHadInitial) {
        mCardPositionInfoList.add(new Pair(new Pair(left, right), new Pair(top, bottom)));
      }
      drawInnerRoundCard(canvas, left, top, right, bottom, i);
    }
    mHadInitial = true;
  } 

全部绘制完成后,在onTouchEvent中处理点击事件即可,如何判定我们点击的是抽奖的区域,这里使用对比位置信息的方法,如下

private int getTouchPositionInCardList(int x, int y) {
    if(mCardPositionInfoList != null) {
      int index = 1;
      for (Pair<Pair<Integer, Integer>,Pair<Integer, Integer>> pair : mCardPositionInfoList) {
        if(x > pair.first.first && x < pair.first.second && y > pair.second.first && y < pair.second.second) {
          return index;
        }
        index++;
      }
    }
    return 0;
  }

将每一个小卡片的坐标信息(left,top, right, bottom)信息,保存在 ArrayList<Pair<Pair<Integer, Integer>,Pair<Integer, Integer>>>  mCardPosttionInfoList 中, 当点击VIew时获取到点击的x y 坐标和

list中保存的坐标信息做对比,如果index == 5 ,则说明点击的是抽奖所在的小卡片区域。

代码托管在: https://github.com/aquarius520/LotteryView  欢迎star fork

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android抽奖轮盘的制作方法

    本文实例为大家分享了Android抽奖轮盘的具体代码,供大家参考,具体内容如下 main布局(图片资源请自行寻找,抱歉) <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_gra

  • Android打造流畅九宫格抽奖活动效果

    因为company项目中需要做九宫格抽奖活动,以前都没有做过类似的功能,虽然之前在浏览大神们的博客中,无意中也看到了好多关于抽奖的项目,但因为项目中没有需要,一直都没有点击进去看.这次不去看估计不行.直到公司计划要做抽奖功能,才迫不得已上网查找demo 网上找了大半天,好不容易找到了几个demo,下载下来,解压缩包发现竟然里面空空如也,只有几张九宫格的图片,害我白白浪费了几个CSDN积分.后面在eoe网站那发现了一个demo,于是好开心,下载下来后马上导入到工程中,运行看了效果,九宫格是出来了,

  • Android实现抽奖转盘实例代码

    本文详述了android抽奖程序的实现方法,程序为一个抽奖大转盘代码,里面定义了很多图形方法和动画. 实现主要功能的SlyderView.java源代码如下: import android.app.Activity; import android.content.Context; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; import android.graphics.Color; import

  • Android App中实现简单的刮刮卡抽奖效果的实例详解

    主要思想: 将一个view设计成多层:背景层,含中奖信息等: 遮盖层,用于刮奖,使用关联一个Bitmap的Canvas 在该Bitmap上,使用它的canvas.drawPath的api来处理 手势滑动(类似刮奖的动作) 使用paint.setXfermode 来进行消除手势滑动区域 public class GuaView extends View { private Bitmap mBitmap; //遮盖的图层 private Canvas mCanvas; //绘制遮盖图层 privat

  • Android中利用SurfaceView制作抽奖转盘的全流程攻略

    一.概述 今天给大家带来SurfaceView的一个实战案例,话说自定义View也是各种写,一直没有写过SurfaceView,这个玩意是什么东西?什么时候用比较好呢? 可以看到SurfaceView也是继承了View,但是我们并不需要去实现它的draw方法来绘制自己,为什么呢? 因为它和View有一个很大的区别,View在UI线程去更新自己:而SurfaceView则在一个子线程中去更新自己:这也显示出了它的优势,当制作游戏等需要不断刷新View时,因为是在子线程,避免了对UI线程的阻塞. 知

  • Android简单实现圆盘抽奖界面

    闲来无事,做了一个简单的抽奖转盘的ui实现,供大家参考 package com.microchange.lucky; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet;

  • js和html5实现手机端刮刮卡抽奖效果完美兼容android/IOS

    绝对值得看的来篇,哈哈.本人亲自完成,有错误请大家指出: 现在的手机完美支持html5,所以如果手机端想要做个抽奖模块的话,用刮刮卡抽奖效果,相信这个互动体验是非常棒的 ​ps:由于本人没有wp8系统的手机,所以没法兼容wp8系统的,目前完美兼容android,IOS 如果要在pc浏览的话,得改下js,目前支持谷歌,火狐,ie>=10,如果网友想要的话我就去写个 代码如下: 复制代码 代码如下: <!DOCTYPE html> <html lang="en"&g

  • Android使用surfaceView自定义抽奖大转盘

    使用surfaceView自定义抽奖大转盘 话不多说,先上效果图 完整代码地址欢迎start 实现思路以及过程 1.首先了解SurfaceView的基本用法,它跟一般的View不太一样,采用的双缓存机制,可以在子线程中绘制View,不会因为绘制耗时而失去流畅性,这也是选择使用SurfaceView去自定义这个抽奖大转盘的原因,毕竟绘制这个转盘的盘块,奖项的图片和文字以及转动都是靠绘制出来的,是一个比较耗时的绘制过程. 2.使用SurfaceView的一般模板样式 一般会用到的成员变量 priva

  • Android自定义View实现QQ运动积分转盘抽奖功能

    因为偶尔关注QQ运动, 看到QQ运动的积分抽奖界面比较有意思,所以就尝试用自定义View实现了下,原本想通过开发者选项查看下界面的一些信息,后来发现积分抽奖界面是在WebView中展示的,应该是在H5页面中用js代码实现的,暂时不去管它了. 这里的自定义View针对的是继承自View的情况,你可以将Canvas想象为画板, Paint为画笔,自定义View的过程和在画板上用画笔作画其实类似,想象在画板上作画的过程,你要画一个多大图形(对应View的测量 onMeasure方法),你要画什么样的图

  • Android自定义View仿微博运动积分动画效果

    自定义View一直是自己的短板,趁着公司项目不紧张的时候,多加强这方面的练习.这一系列文章主要记录自己在自定义View的学习过程中的心得与体会. 刷微博的时候,发现微博运动界面,运动积分的显示有一个很好看的动画效果.OK,就从这个开始我的自定义view之路! 看一下最后的效果图: 分数颜色,分数大小,外圆的颜色,圆弧的颜色都支持自己设置,整体还是和微博那个挺像的.一起看看自定义View是怎样一步一步实现的: 1.自定义view的属性: 在res/values/ 下建立一个attrs.xml ,

  • Android自定义View仿QQ运动步数效果

    本文实例为大家分享了Android QQ运动步数的具体代码,供大家参考,具体内容如下 今天我们实现下面这样的效果: 首先自定义属性: <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyQQStep"> <attr name="out_color" format="colo

  • Android自定义View 仿QQ侧滑菜单的实现代码

    先看看QQ的侧滑效果 分析一下 先上原理图(不知道能否表达的清楚 ==) -首先这里使用了 Android 的HorizontalScrollView 水平滑动布局作为容器,当然我们需要继承它自定义一个侧滑视图 - 这个容器里面有一个父布局(一般用LinerLayout,本demo用的是),这个父布局里面有且只有两个子控件(布局),初始状态菜单页的位置在Y轴上存在偏移这样可以就可以形成主页叠在菜单页的上方的视觉效果:然后在滑动的过程程中 逐渐修正偏移,最后菜单页和主页并排排列.原理搞清了实现起来

  • Android自定义view仿QQ的Tab按钮动画效果(示例代码)

    话不多说 先上效果图 实现其实很简单,先用两张图 一张是背景的图,一张是笑脸的图片,笑脸的图片是白色,可能看不出来.实现思路:主要是再触摸view的时候同时移动这两个图片,但是移动的距离不一样,造成的错位感,代码很简单: import android.content.Context import android.graphics.* import android.util.AttributeSet import android.view.MotionEvent import android.vi

  • Android自定义View实现QQ消息气泡

    本文实例为大家分享了Android自定义View实现QQ消息气泡的具体代码,供大家参考,具体内容如下 效果图: 原理: 控件源码: public class DragView extends View {     private int defaultZoomSize = 8;     //初始化圆的大小     private int initRadius;     //圆1的圆心位置     private PointF center1;     private PointF center2

  • Android自定义View 实现闹钟唤起播放闹钟铃声功能

    先上图看一下闹钟唤期页面的效果 实现的功能: 1:转动的图片根据天气情况更换 2:转动时间可以设置,转动结束,闹铃声音就结束 3:光圈颜色渐变效果 直接上代码啦: package com.yuekong.sirius.extension.customview; import android.animation.Animator; import android.animation.ValueAnimator; import android.content.Context; import andro

  • Android自定义View实现搜索框(SearchView)功能

    概述 在Android开发中,当系统数据项比较多时,常常会在app添加搜索功能,方便用户能快速获得需要的数据.搜索栏对于我们并不陌生,在许多app都能见到它,比如豌豆荚 在某些情况下,我们希望我们的自动补全信息可以不只是纯文本,还可以像豌豆荚这样,能显示相应的图片和其他数据信息,因此Android给我们提供的AutoCompleteTextView往往就不够用,在大多情况下我们都需要自己去实现搜索框. 分析 根据上面这张图,简单分析一下自定义搜索框的结构与功能,有 1. 搜索界面大致由三部门组成

  • Android自定义View仿QQ健康界面

    最近一直在学习自定义View相关的知识,今天给大家带来的是QQ健康界面的实现.先看效果图: 可以设置数字颜色,字体颜色,运动步数,运动排名,运动平均步数,虚线下方的蓝色指示条的长度会随着平均步数改变而进行变化.整体效果还是和QQ运动健康界面很像的. 自定义View四部曲,一起来看看怎么实现的. 1.自定义view的属性: <?xml version="1.0" encoding="utf-8"?> <resources> //自定义属性名,定

  • Android自定义View仿QQ等级天数进度

    最近一直都在看自定义View这一块.差不多一个星期了吧.这个星期坚持每天更新博客,感觉自己的技术也有点突破,对自定义View的计算也有了更深的认识. 今天看到手机一个成长天数进度的控件,觉得挺有意思的,于是想自己也写一个.效果如下: 由图可以知道,这里面有很多个元素,首先是背景的矩形区域,其次就是两个环形,然后三个Text文本.其实不复杂,我们一点一点的去实现. 首先呢,画矩形背景.这里用到一个RectF的类,这个类包含一个矩形的四个单精度浮点坐标.矩形通过上下左右4个边的坐标来表示一个矩形.这

随机推荐