Android 自定義View 抽獎(jiǎng)大轉(zhuǎn)盤(1)

站在別人的肩膀上慢慢前行

只是部分的轉(zhuǎn)盤主要功能的實(shí)現(xiàn)辣恋,其他的東西可以慢慢填上奖亚,這里做一個(gè)簡(jiǎn)單的介紹

鎮(zhèn)樓圖

S71010-17315559.jpg

github鏈接 https://github.com/yukunkun/RotateView
來(lái)源

主要有四部分組成,

1.外部的圓形轉(zhuǎn)盤艾船。2.內(nèi)部的文字顯示。3.內(nèi)部的圖片顯示高每。4.動(dòng)畫實(shí)現(xiàn)屿岂。

在獲取到了數(shù)據(jù)之后,初始化一些數(shù)據(jù)的實(shí)現(xiàn)

private void init(Context context, AttributeSet attrs, int s) {
        this.context = context;
        screeHeight = getResources().getDisplayMetrics().heightPixels;
        screenWidth = getResources().getDisplayMetrics().widthPixels;
        scroller = ScrollerCompat.create(context);
    }

    private void initDate() {
        //數(shù)據(jù)不能錯(cuò)誤
        if(strs.size()!=images.size()||strs.size()==0||images.size()==0){
            return;
        }
        panNum=strs.size();
        //獲取到角度
        InitAngle = 360 / panNum;
        //獲取到角度
        verPanRadius = 360 / panNum;
        //初始角度的一半
        diffRadius = verPanRadius /2;
        //兩個(gè)扇形的顏色
        dPaint.setColor(Color.rgb(255,133,132));
        //兩個(gè)扇形的顏色
        sPaint.setColor(Color.rgb(254,104,105));
        textPaint.setColor(Color.WHITE);
        textPaint.setTextSize(Util.dip2px(context,16));
        setClickable(true);
        for(int i=0;i<panNum;i++){
            Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), images.get(i));
            bitmaps.add(bitmap);
        }
    }

下面是一些方法鲸匿,具體的注釋寫了很多爷怀,可以直接看

  @Override
      protected void onDraw(Canvas canvas) {
          super.onDraw(canvas);
          //內(nèi)邊距
          final int paddingLeft = getPaddingLeft();
          final int paddingRight = getPaddingRight();
          final int paddingTop = getPaddingTop();
          final int paddingBottom = getPaddingBottom();
          //view的寬高
          int width = getWidth() - paddingLeft - paddingRight;
          int height = getHeight() - paddingTop - paddingBottom;
          int MinValue = Math.min(width,height);
          //獲取到圓的半徑
          radius = MinValue/2;
          //獲取到view的矩形
          RectF rectF = new RectF(getPaddingLeft(),getPaddingTop(),width,height);
          //角度的起始是順時(shí)針的,%4==0,如果為4,則就是90度带欢,數(shù)學(xué)的第三象限開(kāi)始霉撵,否則在第四象限
          int angle = (panNum%4 ==0) ? InitAngle : InitAngle-diffRadius;
          Log.d("angle", String.valueOf(angle));
          //繪制圓弧,兩個(gè)不同顏色的圓弧
          for(int i= 0;i<panNum;i++){
              if(i%2 == 0){
                  canvas.drawArc(rectF,angle,verPanRadius,true,dPaint);
              }else {
                  canvas.drawArc(rectF,angle,verPanRadius,true,sPaint);
              }
              angle += verPanRadius;
          }
  
          //繪制圖片
          for(int i=0;i<panNum;i++){
              drawIcon(width/2, height/2, radius, (panNum%4==0)?InitAngle + diffRadius : InitAngle, i, canvas);
              InitAngle += verPanRadius;
          }
          //繪制文字
          for(int i=0;i<panNum;i++){
              drawText((panNum%4==0)?InitAngle+diffRadius + (diffRadius*3/4):InitAngle+diffRadius ,strs.get(i), 2*radius, textPaint, canvas,rectF);
              InitAngle += verPanRadius;
          }
      }

以上是外部繪制洪囤,文字和圖片的繪制

//文字繪制,path路徑
    private void drawText(float startAngle, String string, int mRadius, Paint mTextPaint, Canvas mCanvas, RectF mRange) {
        Path path = new Path();
        path.addArc(mRange, startAngle, verPanRadius);
        float textWidth = mTextPaint.measureText(string);

        //圓弧的水平偏移撕氧,保證在轉(zhuǎn)盤內(nèi)部
        float hOffset  = (panNum % 4 == 0)?((float) (mRadius * Math.PI / panNum/2 ))
                :((float) (mRadius * Math.PI / panNum/2 - textWidth/2 ));
        //圓弧的垂直偏移瘤缩,保證在轉(zhuǎn)盤內(nèi)部
        float vOffset = mRadius / 2 / 6;
        mCanvas.drawTextOnPath(string, path, hOffset, vOffset, mTextPaint);
    }

    private void drawIcon(int xx,int yy,int mRadius,float startAngle, int i,Canvas mCanvas) {

        int imgWidth = mRadius / 4;

        float angle = (float) Math.toRadians(verPanRadius +startAngle);

        //確定圖片在圓弧中 中心點(diǎn)的位置
        float x = (float) (xx + (mRadius /2 + mRadius/12)* Math.cos(angle));
        float y = (float) (yy + (mRadius /2 +mRadius/12) * Math.sin(angle));

        // 確定繪制圖片的位置,前后偏移伦泥,得到圖片的位置
        RectF rect = new RectF(x - imgWidth *2 / 3, y - imgWidth*2 / 3, x + imgWidth
                *2/ 3, y + imgWidth*2/3);
        //mCanvas.drawRect(rect,textPaint);
        Bitmap bitmap = bitmaps.get(i);
        //繪制
        mCanvas.drawBitmap(bitmap, null, rect, null);
    }

具體的繪制和計(jì)算如上所示剥啤,可以實(shí)現(xiàn)轉(zhuǎn)盤的View了。

主要是動(dòng)畫的處理不脯,有點(diǎn)計(jì)算在里面

 //旋轉(zhuǎn)的動(dòng)畫
    public void startAnimation(int pos){

        //Rotate lap. 隨機(jī)的圈數(shù)府怯,>4圈,修改可以控制旋轉(zhuǎn)的圈數(shù)和時(shí)長(zhǎng)
        int lap = (int) (Math.random()*2) + 4;

        //Rotate angle.
        int angle = 0;
        if(pos < 0){
            //隨機(jī)角度
            angle = (int) (Math.random() * 360);
        }else{
            //控制某個(gè)角度防楷,由具體的位置牺丙,計(jì)算出具體的角度值
            int initPos  = queryPosition();
            if(pos > initPos){
                angle = (pos - initPos)*verPanRadius;
                lap -= 1;
                angle = 360 - angle;
            }else if(pos < initPos){
                angle = (initPos - pos)*verPanRadius;
            }else{
                //nothing to do.
            }
        }

        //All of the rotate angle.
        int increaseDegree = lap * 360 + angle;
        long time = (lap + angle / 360) * ONE_WHEEL_TIME;
        int DesRotate = increaseDegree + InitAngle;

        //TODO 為了每次都能旋轉(zhuǎn)到轉(zhuǎn)盤的中間位置
        int offRotate = DesRotate % 360 % verPanRadius;
        DesRotate -= offRotate;
        DesRotate += diffRadius;
        //屬性動(dòng)畫
        ValueAnimator animtor = ValueAnimator.ofInt(InitAngle,DesRotate);
        animtor.setInterpolator(new AccelerateDecelerateInterpolator());
        animtor.setDuration(time);
        animtor.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int updateValue = (int) animation.getAnimatedValue();
                //每次繪制的初始值改變,最終會(huì)停止到之前設(shè)置的角度數(shù)值
                InitAngle = (updateValue % 360 + 360) % 360;
                //重繪制
                ViewCompat.postInvalidateOnAnimation(RotateView.this);
            }
        });
        //動(dòng)畫監(jiān)聽(tīng),獲取到具體的停留位置冲簿,這里處理隨機(jī)位置粟判,其實(shí)提前是知道的
        animtor.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                int pos = InitAngle / 60;
                if(pos >= 0 && pos <= 3){
                    pos = 3 - pos;
                }else{
                    pos = (6-pos) + 3;
                }

                mOnCallBackPosition.getStopPosition(pos);
                //可以回調(diào)出去,得到值
//                Toast.makeText(context, strs.get(pos), Toast.LENGTH_SHORT).show();

            }
        });
        animtor.start();
    }

    //由具體的位置峦剔,獲取到角度
    private int queryPosition(){
        InitAngle = (InitAngle % 360 + 360) % 360;
        int pos = InitAngle / verPanRadius;
        if(panNum == 4) pos ++;
        return calcumAngle(pos);
    }
    private int calcumAngle(int pos){
        if(pos >= 0 && pos <= panNum/2){
            pos = panNum/2 - pos;
        }else{
            pos = (panNum-pos) + panNum/2;
        }
        return pos;
    }

如上所示档礁,動(dòng)畫實(shí)現(xiàn),采用了屬性動(dòng)畫吝沫,多次繪制的方法呻澜,創(chuàng)造出旋轉(zhuǎn)的效果

具體的使用如下

public class MainActivity extends AppCompatActivity {

    private RotateView mRotateView;
    List<Integer> images=new ArrayList<>();
    List<String> names=new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRotateView = (RotateView) findViewById(R.id.rv_rotateview);
        intDate();
        mRotateView.setImageIcon(images);
        mRotateView.setStrName(names);
        findViewById(R.id.iv_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //-1為隨機(jī)數(shù)或者指定位置,但必須小于總個(gè)數(shù)
                mRotateView.startAnimation(-1);
            }
        });

        //獲取到位置
        mRotateView.setOnCallBackPosition(new RotateView.onCallBackPosition() {
            @Override
            public void getStopPosition(int pos) {
                Toast.makeText(MainActivity.this, "位置:"+names.get(pos), Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void intDate() {
        images.add(R.mipmap.role);
        images.add(R.mipmap.sports);
        images.add(R.mipmap.words);
        images.add(R.mipmap.action);
        images.add(R.mipmap.combat);
        images.add(R.mipmap.moba);
        names= Arrays.asList(getResources().getStringArray(R.array.name));
    }
}

就可以實(shí)現(xiàn)旋轉(zhuǎn)的大轉(zhuǎn)盤惨险。還有一部分外圍的框羹幸,之后在添上,主要的大轉(zhuǎn)盤抽獎(jiǎng)功能是實(shí)現(xiàn)了平道。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末睹欲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子一屋,更是在濱河造成了極大的恐慌忧吟,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膏燕,死亡現(xiàn)場(chǎng)離奇詭異献丑,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)诽嘉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門蔚出,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人虫腋,你說(shuō)我怎么就攤上這事骄酗。” “怎么了悦冀?”我有些...
    開(kāi)封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵趋翻,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我盒蟆,道長(zhǎng)踏烙,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任历等,我火速辦了婚禮讨惩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘寒屯。我一直安慰自己荐捻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著靴患,像睡著了一般仍侥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鸳君,一...
    開(kāi)封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天农渊,我揣著相機(jī)與錄音,去河邊找鬼或颊。 笑死砸紊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的囱挑。 我是一名探鬼主播醉顽,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼平挑!你這毒婦竟也來(lái)了游添?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤通熄,失蹤者是張志新(化名)和其女友劉穎唆涝,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體唇辨,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡廊酣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赏枚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片亡驰。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖饿幅,靈堂內(nèi)的尸體忽然破棺而出凡辱,到底是詐尸還是另有隱情,我是刑警寧澤栗恩,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布煞茫,位于F島的核電站,受9級(jí)特大地震影響摄凡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蚓曼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一亲澡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纫版,春花似錦床绪、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)膀斋。三九已至,卻和暖如春痹雅,著一層夾襖步出監(jiān)牢的瞬間仰担,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工绩社, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留摔蓝,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓愉耙,卻偏偏與公主長(zhǎng)得像贮尉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子朴沿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,732評(píng)論 25 707
  • 1 背景 不能只分析源碼呀猜谚,分析的同時(shí)也要整理歸納基礎(chǔ)知識(shí),剛好有人微博私信讓全面說(shuō)說(shuō)Android的動(dòng)畫赌渣,所以今...
    未聞椛洺閱讀 2,697評(píng)論 0 10
  • 轉(zhuǎn)載一篇高質(zhì)量博文魏铅,原地址請(qǐng)戳這里轉(zhuǎn)載下來(lái)方便今后查看。1 背景不能只分析源碼呀锡垄,分析的同時(shí)也要整理歸納基礎(chǔ)知識(shí)沦零,...
    Elder閱讀 1,938評(píng)論 0 24
  • 9月21日今天加班回家晚了一些,昊臻在托福完成了大部分作業(yè)货岭,因?yàn)橛星败囍b不敢麻痹大意路操,回到家后把他的作業(yè)重新檢查...
    秦昊臻閱讀 244評(píng)論 0 0
  • 周末天氣晴朗,溫度適宜千贯,但還是有嚴(yán)重的霧霾屯仗。一人無(wú)事,想出去走走搔谴,正巧住的地方一趟公交直達(dá)水上公園魁袜,于是前往。 水...
    _hou閱讀 674評(píng)論 0 45