当前位置: 移动技术网 > IT编程>移动开发>Android > Android实现可点击的幸运大转盘

Android实现可点击的幸运大转盘

2019年07月29日  | 移动技术网IT编程  | 我要评论

黑牡丹花图片,红蓝黄幼儿园事件,beautiful 仓木麻衣

之前的项目有一个幸运大转盘的功能,在网上找了很久,都没有合适的方法。


这是效果图,实现目标:十二星座的图片可点击切换选中效果,根据选择不同的星座,实现不同的 方法。之前网上的都是带有指针的,或者可点击改变效果,但是并不知道选择的到底是哪个,即虚拟选择。

实现该功能的主要代码如下:

1、自定义一个布局,存放图片,实现圆形布局。

/**
 *
 *
 * circlemenulayout.java
 *
 * @author wuxiaosu
 *
 */
public class circlemenulayout extends viewgroup {
  /**
   * 布局的半径
   */
  private int mradius;
  /**
   * 该容器内child item的默认尺寸
   */
  private static final float radio_default_child_dimension = 1f;
  /**
   * 菜单的中心child的默认尺寸
   */
  private float radio_default_centeritem_dimension = 1 / 3f;
  /**
   * 该容器的内边距,无视padding属性,如需边距请用该变量
   */
  private static final float radio_padding_layout = 1 / 12f;
  /**
   * 该容器的内边距,无视padding属性,如需边距请用该变量
   */
  private float mpadding;
  /**
   * 布局时的开始角度
   */
  private double mstartangle = 0;
  /**
   * 菜单项的文本
   */
  private string[] mitemtexts;
  /**
   * 菜单项的图标
   */
  private int[] mitemimgs;

  /**
   * 菜单的个数
   */
  private int mmenuitemcount;

  private int mmenuitemlayoutid = r.layout.circle_menu_item;

  public circlemenulayout(context context, attributeset attrs) {
    super(context, attrs);
    // 无视padding
    setpadding(0, 0, 0, 0);
  }

  /**
   * 设置布局的宽高,并策略menu item宽高
   */
  @override
  protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
    /**
     * 整个圆盘布局 的宽高
     */
    int reswidth = 0;
    int resheight = 0;

    /**
     * 根据传入的参数,分别获取测量模式和测量值ֵ
     */
    int width = measurespec.getsize(widthmeasurespec);
    int widthmode = measurespec.getmode(widthmeasurespec);

    int height = measurespec.getsize(heightmeasurespec);
    int heightmode = measurespec.getmode(heightmeasurespec);

    /**
     * 如果宽或者高的测量模式非精确值ֵ
     */
    if (widthmode != measurespec.exactly
        || heightmode != measurespec.exactly) {
      // 主要设置为背景图的高度
      reswidth = getsuggestedminimumwidth();
      // 如果未设置背景图片,则设置为屏幕宽高的默认值ֵ
      reswidth = reswidth == 0 ? getdefaultwidth() : reswidth;

      resheight = getsuggestedminimumheight();
      // 如果未设置背景图片,则设置为屏幕宽高的默认值ֵ
      resheight = resheight == 0 ? getdefaultwidth() : resheight;
    } else {
      // 如果都设置为精确值,则直接取小值;
      reswidth = resheight = math.min(width, height);
    }

    log.e("tag", "reswidth = " + reswidth + ", resheight = " + resheight);

    setmeasureddimension(reswidth, resheight);

    // 获得半径
    mradius = math.max(getmeasuredwidth(), getmeasuredheight());

    // menu item数量
    final int count = getchildcount();
    // menu item尺寸
    int childsize = (int) (mradius * radio_default_child_dimension);
    log.e("tag", "childsize = " + childsize);
    // menu item测量模式
    int childmode = measurespec.exactly;

    // 迭代测量
    for (int i = 0; i < count; i++) {
      final view child = getchildat(i);

      if (child.getvisibility() == gone) {
        continue;
      }

      // 计算menu item的尺寸;以及和设置好的模式,去对item进行测量
      int makemeasurespec = -1;

      if (child.getid() == r.id.id_circle_menu_item_center) {
        makemeasurespec = measurespec.makemeasurespec(
            (int) (mradius * radio_default_centeritem_dimension),
            childmode);
      } else {
        makemeasurespec = measurespec.makemeasurespec(childsize,
            childmode);
      }
      child.measure(makemeasurespec, makemeasurespec);
    }

    mpadding = radio_padding_layout * mradius;

  }

  /**
   * menuitem的点击事件接口
   * 
   * 
   */
  public interface onmenuitemclicklistener {
    void itemclick(view view, int pos);

    void itemcenterclick(view view);
  }

  /**
   * menuitem的点击事件接口
   */
  private onmenuitemclicklistener monmenuitemclicklistener;

  /**
   * 设置menuitem的点击事件接口
   * 
   * @param monmenuitemclicklistener
   */
  public void setonmenuitemclicklistener(
      onmenuitemclicklistener monmenuitemclicklistener) {
    this.monmenuitemclicklistener = monmenuitemclicklistener;
  }

  /**
   * 设置menu item的位置
   */
  @suppresslint("newapi")
  @override
  protected void onlayout(boolean changed, int l, int t, int r, int b) {
    int layoutradius = mradius;
    log.e("tag", "layoutradius = " + layoutradius);

    // laying out the child views
    final int childcount = getchildcount();

    int left, top;
    // menu item 的尺寸
    int cwidth = (int) (layoutradius * radio_default_child_dimension);

    // 根据menu item的个数,计算角度
    float angledelay = 0;
    if ((getchildcount() - 1) != 0) {
      angledelay = 360 / (getchildcount() - 1);
    }
    angledelay = 30f;
    log.e("tag", "单个角度 angledelay = " + angledelay);

    // 遍历去设置menuitem的位置
    for (int i = 0; i < childcount; i++) {
      final view child = getchildat(i);

      if (child.getid() == r.id.id_circle_menu_item_center)
        continue;

      if (child.getvisibility() == gone) {
        continue;
      }

      mstartangle %= 360;

      // 计算,中心点到menu item中心的距离--即图片中心位置到圆心的距离
      float tmp = layoutradius / 2f - cwidth / 2 - mpadding;
      // 根据屏幕密度计算,基数为60(暂定60)
      tmp = luckyutil.getdensity() * 57;
      log.e("tag", "tmp = " + tmp);

      // tmp cosa 即menu item中心点的横坐标
      left = layoutradius
          / 2
          + (int) math.round(tmp
              * math.cos(math.toradians(mstartangle)) - 1 / 2f
              * cwidth);
      // tmp sina 即menu item的纵坐标
      top = layoutradius
          / 2
          + (int) math.round(tmp
              * math.sin(math.toradians(mstartangle)) - 1 / 2f
              * cwidth);

      child.layout(left, top, left + cwidth, top + cwidth);
      // 叠加尺寸
      mstartangle += angledelay;
    }

    // 找到中心的view,如果存在设置onclick事件
    view cview = findviewbyid(r.id.id_circle_menu_item_center);
    if (cview != null) {
      cview.setonclicklistener(new onclicklistener() {
        @suppresslint("drawallocation")
        @override
        public void onclick(view v) {

          if (monmenuitemclicklistener != null) {
            monmenuitemclicklistener.itemcenterclick(v);
          }
        }
      });
      // 设置center item位置
      int cl = layoutradius / 2 - cview.getmeasuredwidth() / 2;
      int cr = cl + cview.getmeasuredwidth();
      cview.layout(cl, cl, cr, cr);
    }

  }

  /**
   * 主要为了action_down时,返回true
   */
  @override
  public boolean ontouchevent(motionevent event) {
    return true;
  }

  /**
   * 设置菜单条目的图标和文本
   * 
   * @param resids
   */
  public void setmenuitemiconsandtexts(int[] resids, string[] texts) {
    mitemimgs = resids;
    mitemtexts = texts;

    // 参数检查
    if (resids == null && texts == null) {
      throw new illegalargumentexception("菜单项文本和图片至少设置其一");
    }

    // 初始化mmenucount
    mmenuitemcount = resids == null ? texts.length : resids.length;

    if (resids != null && texts != null) {
      mmenuitemcount = math.min(resids.length, texts.length);
    }

    addmenuitems();

  }

  /**
   * 设置menuitem的布局文件,必须在setmenuitemiconsandtexts之前调用
   * 
   * @param mmenuitemlayoutid
   */
  public void setmenuitemlayoutid(int mmenuitemlayoutid) {
    this.mmenuitemlayoutid = mmenuitemlayoutid;
  }

  /**
   * 添加菜单项
   */
  @suppresslint("newapi")
  private void addmenuitems() {
    layoutinflater minflater = layoutinflater.from(getcontext());

    /**
     * 根据用户设置的参数,初始化view
     */
    for (int i = 0; i < mmenuitemcount; i++) {
      final int j = i;
      view view = minflater.inflate(mmenuitemlayoutid, this, false);
      imageview iv = (imageview) view
          .findviewbyid(r.id.id_circle_menu_item_image);

      if (iv != null) {
        iv.setvisibility(view.visible);
        iv.setimageresource(mitemimgs[i]);
        iv.setonclicklistener(new onclicklistener() {
          @override
          public void onclick(view v) {

            if (monmenuitemclicklistener != null) {
              monmenuitemclicklistener.itemclick(v, j);
            }
          }
        });
      }

      // 设置角度
      view.setrotation(90 + i * (360 / (mmenuitemcount)));

      log.e("tag", "旋转角度 = " + (i * (360 / mmenuitemcount)));

      // 添加view到容器中
      addview(view);
    }
  }

  /**
   * 获得默认该layout的尺寸
   * 
   * @return
   */
  private int getdefaultwidth() {
    windowmanager wm = (windowmanager) getcontext().getsystemservice(
        context.window_service);
    displaymetrics outmetrics = new displaymetrics();
    wm.getdefaultdisplay().getmetrics(outmetrics);
    return math.min(outmetrics.widthpixels, outmetrics.heightpixels);
  }

}

(该自定义布局参考了网上一个建行demo的布局,具体的忘记了,请见谅。)

2、xml布局

 <com.zhcl.yqwan.lucky.rotation.circle.circlemenulayout
            android:id="@+id/id_menulayout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="@drawable/ratote_bg_two" >

            <relativelayout
              android:id="@+id/id_circle_menu_item_center"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:visibility="gone" >
            </relativelayout>
          </com.zhcl.yqwan.lucky.rotation.circle.circlemenulayout>

该处主要是自定义控件使用位置的布局。

3、activity中调用

/**
   * 设置属性或者星座的图片,并绘制图形
   * 
   * @param def
   * @param img
   * @param selectedimg
   * @param str
   * @param type
   *      :区分星座和生肖,1--星座,2--生肖。
   */
  private void setrotateselectedimg(final int[] def, final int[] img,
      final int[] selectedimg, string[] str, final int type) {
    mcirclemenulayout.setmenuitemiconsandtexts(def, str);

    mcirclemenulayout
        .setonmenuitemclicklistener(new onmenuitemclicklistener() {

          @override
          public void itemclick(view view, int pos) {
            // 如果是第一次进来,将之前默认选中的item改变为原来的颜色
            // 如果选中的index和默认的index不同,则将默认的设置为原来的颜色
            // toast.maketext(lotteryrotationactivity.this,
            // "pos = " + pos, toast.length_short).show();

            // 选中的index
            selectedindex = pos;

            if (pos != 0 && type == 1) {
              img[0] = mconstellationimgs[0];
            } else if (pos != 0 && type == 2) {
              img[0] = manimalimgs[0];
            }

            mcirclemenulayout.removeallviews();
            // mcirclemenulayout = (circlemenulayout)
            // findviewbyid(r.id.id_menulayout);
            // 替换选中的图片
            replaceimg = img[pos];
            img[pos] = selectedimg[pos];
            // 设置图片
            mcirclemenulayout.setmenuitemiconsandtexts(img,
                mitemtexts);
            // 还原图片,方便下一次点击替换
            img[pos] = replaceimg;
          }

          @override
          public void itemcenterclick(view view) {

          }
        });

  }


// 星座:最开始默认选择一个
    setrotateselectedimg(mconstellationimgsdefult, mconstellationimgs,
        mconstellationimgsselected, manimalstr, 1);

这里定义了一个setrotateselectedimg的方法,方便使用,其中final int[] def, final int[] img,final int[] selectedimg, 是三个图片数组,分别是初始化时默认的选中状态的图片数组(有一个被选中)、全部未选中的图片数组、选中后的图片数组(不同于默认的图片数组),string[] str是字符串数组,由于文字已经在切图中给出,此处可忽略。

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网