当前位置: 移动技术网 > 移动技术>移动开发>Android > 基于Android实现转盘按钮代码

基于Android实现转盘按钮代码

2019年07月24日  | 移动技术网移动技术  | 我要评论

先给大家展示下效果图:

package com.lixu.circlemenu;
 import android.app.activity;
 import android.os.bundle;
 import android.view.view;
 import android.widget.textview;
 import android.widget.toast;
 import com.lixu.circlemenu.view.circleimageview;
 import com.lixu.circlemenu.view.circlelayout;
 import com.lixu.circlemenu.view.circlelayout.onitemclicklistener;
 import com.lixu.circlemenu.view.circlelayout.onitemselectedlistener;
 import com.szugyi.circlemenu.r;
 public class mainactivity extends activity implements onitemselectedlistener, onitemclicklistener{
   private  textview selectedtextview;
   @override
   protected void oncreate(bundle savedinstancestate) {
     super.oncreate(savedinstancestate);
     setcontentview(r.layout.activity_main);
     circlelayout circlemenu = (circlelayout)findviewbyid(r.id.main_circle_layout);
     circlemenu.setonitemselectedlistener(this);
     circlemenu.setonitemclicklistener(this);
     //这个textview仅仅作为演示转盘按钮以何为默认的选中项,
     //默认的最底部的那一条被选中,然后显示到该textview中。
     selectedtextview = (textview)findviewbyid(r.id.main_selected_textview);
     selectedtextview.settext(((circleimageview)circlemenu.getselecteditem()).getname());
   }
   //圆盘转动到底部,则认为该条目被选中
   @override
   public void onitemselected(view view, int position, long id, string name) {    
     selectedtextview.settext(name);
   }
   //选择了转盘中的某一条。
   @override
   public void onitemclick(view view, int position, long id, string name) {
     toast.maketext(getapplicationcontext(), getresources().getstring(r.string.start_app) + " " + name, toast.length_short).show();
   }
 }

引用两个开源类:

 package com.lixu.circlemenu.view;
 /*
  * copyright csaba szugyiczki
  *
  * licensed under the apache license, version . (the "license");
  * you may not use this file except in compliance with the license.
  * you may obtain a copy of the license at
  *
 *   http://www.apache.org/licenses/license-.
 *
 * unless required by applicable law or agreed to in writing, software
 * distributed under the license is distributed on an "as is" basis,
 * without warranties or conditions of any kind, either express or implied.
 * see the license for the specific language governing permissions and
 * limitations under the license.
 */
 import android.content.context;
 import android.content.res.typedarray;
 import android.util.attributeset;
 import android.widget.imageview;
 import com.szugyi.circlemenu.r;
 /**
 * 
 * @author szugyi
 * custom imageview for the circlelayout class.
 * makes it possible for the image to have an angle, position and a name.
 * angle is used for the positioning in the circle menu.
 */
 public class circleimageview extends imageview {
   private float angle = ;
   private int position = ;
   private string name;
   public float getangle() {
     return angle;
   }
   public void setangle(float angle) {
     this.angle = angle;
   }
   public int getposition() {
     return position;
   }
   public void setposition(int position) {
     this.position = position;
   }
   public string getname(){
     return name;
   }
   public void setname(string name){
     this.name = name;
   }
   /**
   * @param context
   */
   public circleimageview(context context) {
     this(context, null);
   }
   /**
   * @param context
   * @param attrs
   */
   public circleimageview(context context, attributeset attrs) {
     this(context, attrs, );
   }
   /**
   * @param context
   * @param attrs
   * @param defstyle
   */
   public circleimageview(context context, attributeset attrs, int defstyle) {
     super(context, attrs, defstyle);
     if (attrs != null) {
       typedarray a = getcontext().obtainstyledattributes(attrs,
           r.styleable.circleimageview);
       name = a.getstring(r.styleable.circleimageview_name);
     }
   }
 }

  package com.lixu.circlemenu.view;
  import com.szugyi.circlemenu.r;
  /*
  * copyright csaba szugyiczki
  *
  * licensed under the apache license, version . (the "license");
  * you may not use this file except in compliance with the license.
  * you may obtain a copy of the license at
  *
  *   http://www.apache.org/licenses/license-.
  *
  * unless required by applicable law or agreed to in writing, software
  * distributed under the license is distributed on an "as is" basis,
  * without warranties or conditions of any kind, either express or implied.
  * see the license for the specific language governing permissions and
  * limitations under the license.
  */
 import android.content.context;
 import android.content.res.typedarray;
 import android.graphics.bitmap;
 import android.graphics.bitmapfactory;
 import android.graphics.canvas;
 import android.graphics.matrix;
 import android.util.attributeset;
 import android.view.gesturedetector;
 import android.view.gesturedetector.simpleongesturelistener;
 import android.view.motionevent;
 import android.view.view;
 import android.view.viewgroup;
 /**
  * 
  * @author szugyi
  * creates a rotatable circle menu which can be parameterized by custom attributes.
  * handles touches and gestures to make the menu rotatable, and to make the 
  * menu items selectable and clickable.
  * 
  */
 public class circlelayout extends viewgroup {
   // event listeners
   private onitemclicklistener monitemclicklistener = null;
   private onitemselectedlistener monitemselectedlistener = null;
   private oncenterclicklistener moncenterclicklistener = null;
   // background image
   private bitmap imageoriginal, imagescaled;
   private matrix matrix;
   private int mtappedviewspostition = -;
   private view mtappedview = null;
   private int selected = ;
   // child sizes
   private int mmaxchildwidth = ;
   private int mmaxchildheight = ;
   private int childwidth = ;
   private int childheight = ;
   // sizes of the viewgroup
   private int circlewidth, circleheight;
   private int radius = ;
   // touch detection
   private gesturedetector mgesturedetector;
   // needed for detecting the inversed rotations
   private boolean[] quadranttouched;
   // settings of the viewgroup
   private boolean allowrotating = true;
   private float angle = ;
   private float firstchildpos = ;
   private boolean rotatetocenter = true;
   private boolean isrotating = true;
   /**
    * @param context
    */
   public circlelayout(context context) {
     this(context, null);
   }
   /**
    * @param context
    * @param attrs
    */
   public circlelayout(context context, attributeset attrs) {
     this(context, attrs, );
   }
   /**
    * @param context
    * @param attrs
    * @param defstyle
    */
   public circlelayout(context context, attributeset attrs, int defstyle) {
     super(context, attrs, defstyle);
     init(attrs);
   }
   /**
   * initializes the viewgroup and modifies it's default behavior by the passed attributes
   * @param attrs  the attributes used to modify default settings
   */
   protected void init(attributeset attrs) {
     mgesturedetector = new gesturedetector(getcontext(),
         new mygesturelistener());
     quadranttouched = new boolean[] { false, false, false, false, false };
     if (attrs != null) {
       typedarray a = getcontext().obtainstyledattributes(attrs,
           r.styleable.circle);
       // the angle where the first menu item will be drawn
       angle = a.getint(r.styleable.circle_firstchildposition, );
       firstchildpos = angle;
       rotatetocenter = a.getboolean(r.styleable.circle_rotatetocenter,
           true);      
       isrotating = a.getboolean(r.styleable.circle_isrotating, true);
       // if the menu is not rotating then it does not have to be centered
       // since it cannot be even moved
       if (!isrotating) {
         rotatetocenter = false;
       }
       if (imageoriginal == null) {
         int picid = a.getresourceid(
             r.styleable.circle_circlebackground, -);
         // if a background image was set as an attribute, 
         // retrieve the image
         if (picid != -) {
           imageoriginal = bitmapfactory.decoderesource(
               getresources(), picid);
         }
       }
       a.recycle();
       // initialize the matrix only once
       if (matrix == null) {
         matrix = new matrix();
       } else {
         // not needed, you can also post the matrix immediately to
         // restore the old state
         matrix.reset();
       }
       // needed for the viewgroup to be drawn
       setwillnotdraw(false);
     }
   }
   /**
   * returns the currently selected menu
   * @return the view which is currently the closest to the start position
   */
   public view getselecteditem() {
     return (selected >= ) ? getchildat(selected) : null;
   }
   @override
   protected void ondraw(canvas canvas) {
     // the sizes of the viewgroup
     circleheight = getheight();
     circlewidth = getwidth();
     if (imageoriginal != null) {
       // scaling the size of the background image
       if (imagescaled == null) {
         matrix = new matrix();
         float sx = (((radius + childwidth / ) * ) / (float) imageoriginal
             .getwidth());
         float sy = (((radius + childwidth / ) * ) / (float) imageoriginal
             .getheight());
         matrix.postscale(sx, sy);
         imagescaled = bitmap.createbitmap(imageoriginal, , ,
             imageoriginal.getwidth(), imageoriginal.getheight(),
             matrix, false);
       }
       if (imagescaled != null) {
         // move the background to the center
         int cx = (circlewidth - imagescaled.getwidth()) / ;
         int cy = (circleheight - imagescaled.getheight()) / ;
         canvas g = canvas;
         canvas.rotate(, circlewidth / , circleheight / );
         g.drawbitmap(imagescaled, cx, cy, null);
       }
     }
   }
   @override
   protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
     mmaxchildwidth = ;
     mmaxchildheight = ;
     // measure once to find the maximum child size.
     int childwidthmeasurespec = measurespec.makemeasurespec(
         measurespec.getsize(widthmeasurespec), measurespec.at_most);
     int childheightmeasurespec = measurespec.makemeasurespec(
         measurespec.getsize(widthmeasurespec), measurespec.at_most);
     final int count = getchildcount();
     for (int i = ; i < count; i++) {
       final view child = getchildat(i);
       if (child.getvisibility() == gone) {
         continue;
       }
       child.measure(childwidthmeasurespec, childheightmeasurespec);
       mmaxchildwidth = math.max(mmaxchildwidth, child.getmeasuredwidth());
       mmaxchildheight = math.max(mmaxchildheight,
           child.getmeasuredheight());
     }
     // measure again for each child to be exactly the same size.
     childwidthmeasurespec = measurespec.makemeasurespec(mmaxchildwidth,
         measurespec.exactly);
     childheightmeasurespec = measurespec.makemeasurespec(mmaxchildheight,
         measurespec.exactly);
     for (int i = ; i < count; i++) {
       final view child = getchildat(i);
       if (child.getvisibility() == gone) {
         continue;
       }
       child.measure(childwidthmeasurespec, childheightmeasurespec);
     }
     setmeasureddimension(resolvesize(mmaxchildwidth, widthmeasurespec),
         resolvesize(mmaxchildheight, heightmeasurespec));
   }
   @override
   protected void onlayout(boolean changed, int l, int t, int r, int b) {
     int layoutwidth = r - l;
     int layoutheight = b - t;
     // laying out the child views
     final int childcount = getchildcount();
     int left, top;
     radius = (layoutwidth <= layoutheight) ? layoutwidth / 
         : layoutheight / ;
     childwidth = (int) (radius / .);
     childheight = (int) (radius / .);
     float angledelay = / getchildcount();
     for (int i = ; i < childcount; i++) {
       final circleimageview child = (circleimageview) getchildat(i);
       if (child.getvisibility() == gone) {
         continue;
       }
       if (angle > ) {
         angle -= ;
       } else {
         if (angle < ) {
           angle += ;
         }
       }
       child.setangle(angle);
       child.setposition(i);
       left = math
           .round((float) (((layoutwidth / ) - childwidth / ) + radius
               * math.cos(math.toradians(angle))));
       top = math
           .round((float) (((layoutheight / ) - childheight / ) + radius
               * math.sin(math.toradians(angle))));
       child.layout(left, top, left + childwidth, top + childheight);
       angle += angledelay;
     }
   }
   /**
   * rotate the buttons.
   * 
   * @param degrees the degrees, the menu items should get rotated.
   */
   private void rotatebuttons(float degrees) {
     int left, top, childcount = getchildcount();
     float angledelay = / childcount;
     angle += degrees;
     if (angle > ) {
       angle -= ;
     } else {
       if (angle < ) {
         angle += ;
       }
     }
     for (int i = ; i < childcount; i++) {
       if (angle > ) {
         angle -= ;
       } else {
         if (angle < ) {
           angle += ;
         }
       }
       final circleimageview child = (circleimageview) getchildat(i);
       if (child.getvisibility() == gone) {
         continue;
       }
       left = math
           .round((float) (((circlewidth / ) - childwidth / ) + radius
               * math.cos(math.toradians(angle))));
       top = math
           .round((float) (((circleheight / ) - childheight / ) + radius
               * math.sin(math.toradians(angle))));
       child.setangle(angle);
       if (math.abs(angle - firstchildpos) < (angledelay / )
           && selected != child.getposition()) {
         selected = child.getposition();
         if (monitemselectedlistener != null && rotatetocenter) {
           monitemselectedlistener.onitemselected(child, selected,
               child.getid(), child.getname());
         }
       }
       child.layout(left, top, left + childwidth, top + childheight);
       angle += angledelay;
     }
   }
   /**
   * @return the angle of the unit circle with the image view's center
   */
   private double getangle(double xtouch, double ytouch) {
     double x = xtouch - (circlewidth / d);
     double y = circleheight - ytouch - (circleheight / d);
     switch (getquadrant(x, y)) {
     case :
       return math.asin(y / math.hypot(x, y)) * / math.pi;
     case :
     case :
       return - (math.asin(y / math.hypot(x, y)) * / math.pi);
     case :
       return + math.asin(y / math.hypot(x, y)) * / math.pi;
     default:
       // ignore, does not happen
       return ;
     }
   }
   /**
   * @return the selected quadrant.
   */
   private static int getquadrant(double x, double y) {
     if (x >= ) {
       return y >= ? : ;
     } else {
       return y >= ? : ;
     }
   }
   private double startangle;
   @override
   public boolean ontouchevent(motionevent event) {
     if (isenabled()) {
       if (isrotating) {
         switch (event.getaction()) {
         case motionevent.action_down:
           // reset the touched quadrants
           for (int i = ; i < quadranttouched.length; i++) {
             quadranttouched[i] = false;
           }
           allowrotating = false;
           startangle = getangle(event.getx(), event.gety());
           break;
         case motionevent.action_move:
           double currentangle = getangle(event.getx(), event.gety());
           rotatebuttons((float) (startangle - currentangle));
           startangle = currentangle;
           break;
         case motionevent.action_up:
           allowrotating = true;
           rotateviewtocenter((circleimageview) getchildat(selected),
               false);
           break;
         }
       }
       // set the touched quadrant to true
       quadranttouched[getquadrant(event.getx() - (circlewidth / ),
           circleheight - event.gety() - (circleheight / ))] = true;
       mgesturedetector.ontouchevent(event);
       return true;
     }
     return false;
   }
   private class mygesturelistener extends simpleongesturelistener {
     @override
     public boolean onfling(motionevent e, motionevent e, float velocityx,
         float velocityy) {
       if (!isrotating) {
         return false;
       }
       // get the quadrant of the start and the end of the fling
       int q = getquadrant(e.getx() - (circlewidth / ), circleheight
           - e.gety() - (circleheight / ));
       int q = getquadrant(e.getx() - (circlewidth / ), circleheight
           - e.gety() - (circleheight / ));
       // the inversed rotations
       if ((q == && q == && math.abs(velocityx) < math
           .abs(velocityy))
           || (q == && q == )
           || (q == && q == )
           || (q == && q == && math.abs(velocityx) > math
               .abs(velocityy))
           || ((q == && q == ) || (q == && q == ))
           || ((q == && q == ) || (q == && q == ))
           || (q == && q == && quadranttouched[])
           || (q == && q == && quadranttouched[])) {
         circlelayout.this.post(new flingrunnable(-
             * (velocityx + velocityy)));
       } else {
         // the normal rotation
         circlelayout.this
             .post(new flingrunnable(velocityx + velocityy));
       }
       return true;
     }
     @override
     public boolean onsingletapup(motionevent e) {
       mtappedviewspostition = pointtoposition(e.getx(), e.gety());
       if (mtappedviewspostition >= ) {
         mtappedview = getchildat(mtappedviewspostition);
         mtappedview.setpressed(true);
       } else {
         float centerx = circlewidth / ;
         float centery = circleheight / ;
         if (e.getx() < centerx + (childwidth / )
             && e.getx() > centerx - childwidth / 
             && e.gety() < centery + (childheight / )
             && e.gety() > centery - (childheight / )) {
           if (moncenterclicklistener != null) {
             moncenterclicklistener.oncenterclick();
             return true;
           }
         }
       }
       if (mtappedview != null) {
         circleimageview view = (circleimageview) (mtappedview);
         if (selected != mtappedviewspostition) {
           rotateviewtocenter(view, false);
           if (!rotatetocenter) {
             if (monitemselectedlistener != null) {
               monitemselectedlistener.onitemselected(mtappedview,
                   mtappedviewspostition, mtappedview.getid(), view.getname());
             }
             if (monitemclicklistener != null) {
               monitemclicklistener.onitemclick(mtappedview,
                   mtappedviewspostition, mtappedview.getid(), view.getname());
             }
           }
         } else {
           rotateviewtocenter(view, false);
           if (monitemclicklistener != null) {
             monitemclicklistener.onitemclick(mtappedview,
                 mtappedviewspostition, mtappedview.getid(), view.getname());
           }
         }
         return true;
       }
       return super.onsingletapup(e);
     }
   }
   /**
   * rotates the given view to the center of the menu.
   * @param view      the view to be rotated to the center
   * @param fromrunnable  if the method is called from the runnable which animates the rotation
   *             then it should be true, otherwise false 
   */
   private void rotateviewtocenter(circleimageview view, boolean fromrunnable) {
     if (rotatetocenter) {
       float velocitytemp = ;
       float destangle = (float) (firstchildpos - view.getangle());
       float startangle = ;
       int reverser = ;
       if (destangle < ) {
         destangle += ;
       }
       if (destangle > ) {
         reverser = -;
         destangle = - destangle;
       }
       while (startangle < destangle) {
         startangle += velocitytemp / ;
         velocitytemp *= .f;
       }
       circlelayout.this.post(new flingrunnable(reverser * velocitytemp,
           !fromrunnable));
     }
   }
   /**
   * a {@link runnable} for animating the menu rotation.
   */
   private class flingrunnable implements runnable {
     private float velocity;
     float angledelay;
     boolean isfirstforwarding = true;
     public flingrunnable(float velocity) {
       this(velocity, true);
     }
     public flingrunnable(float velocity, boolean isfirst) {
       this.velocity = velocity;
       this.angledelay = / getchildcount();
       this.isfirstforwarding = isfirst;
     }
     public void run() {
       if (math.abs(velocity) > && allowrotating) {
         if (rotatetocenter) {
           if (!(math.abs(velocity) < && (math.abs(angle
               - firstchildpos)
               % angledelay < ))) {
             rotatebuttons(velocity / );
             velocity /= .f;
             circlelayout.this.post(this);
           }
         } else {
           rotatebuttons(velocity / );
           velocity /= .f;
           circlelayout.this.post(this);
         }
       } else {
         if (isfirstforwarding) {
           isfirstforwarding = false;
           circlelayout.this.rotateviewtocenter(
               (circleimageview) getchildat(selected), true);
         }
       }
     }
   }
   private int pointtoposition(float x, float y) {
     for (int i = ; i < getchildcount(); i++) {
       view item = (view) getchildat(i);
       if (item.getleft() < x && item.getright() > x & item.gettop() < y
           && item.getbottom() > y) {
         return i;
       }
     }
     return -;
   }
   public void setonitemclicklistener(onitemclicklistener onitemclicklistener) {
     this.monitemclicklistener = onitemclicklistener;
   }
   public interface onitemclicklistener {
     void onitemclick(view view, int position, long id, string name);
   }
   public void setonitemselectedlistener(
       onitemselectedlistener onitemselectedlistener) {
     this.monitemselectedlistener = onitemselectedlistener;
   }
   public interface onitemselectedlistener {
     void onitemselected(view view, int position, long id, string name);
   }
   public interface oncenterclicklistener {
     void oncenterclick();
   }
   public void setoncenterclicklistener(
       oncenterclicklistener oncenterclicklistener) {
     this.moncenterclicklistener = oncenterclicklistener;
   }
 }

xml文件:
 
  <relativelayout xmlns:android=""
      xmlns:circle=""
      xmlns:tools=""
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:context=".mainactivity" >
      <com.lixu.circlemenu.view.circlelayout
          android:id="@+id/main_circle_layout"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
         android:layout_above="@+id/main_selected_textview"
         android:layout_gravity="center_horizontal"
         circle:firstchildposition="south"
         circle:rotatetocenter="true"
         circle:isrotating="true" >      
 <!--         circle:circlebackground="@drawable/green"  > -->
         <com.lixu.circlemenu.view.circleimageview
             android:id="@+id/main_facebook_image"
             android:layout_width="dp"
             android:layout_height="dp"
             android:src="@drawable/icon_facebook"
             circle:name="@string/facebook" />
         <com.lixu.circlemenu.view.circleimageview
             android:id="@+id/main_myspace_image"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:src="@drawable/icon_myspace"
             circle:name="@string/myspace" />
         <com.lixu.circlemenu.view.circleimageview
             android:id="@+id/main_google_image"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:src="@drawable/icon_google"
             circle:name="@string/google" />
         <com.lixu.circlemenu.view.circleimageview
             android:id="@+id/main_linkedin_image"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:src="@drawable/icon_linkedin"
             circle:name="@string/linkedin" />
         <com.lixu.circlemenu.view.circleimageview
             android:id="@+id/main_twitter_image"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:src="@drawable/icon_twitter"
             circle:name="@string/twitter" />
         <com.lixu.circlemenu.view.circleimageview
             android:id="@+id/main_wordpress_image"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:src="@drawable/icon_wordpress"
             circle:name="@string/wordpress" />
     </com.lixu.circlemenu.view.circlelayout>
     <textview
         android:id="@+id/main_selected_textview"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignparentbottom="true"
         android:layout_centerhorizontal="true"
         android:layout_marginbottom="dp"
         android:textappearance="?android:attr/textappearancelarge" />
 </relativelayout>

基于android实现转盘按钮代码的全部内容就到此结束了,希望能够帮助到大家。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网