欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

基于Android实现转盘按钮代码

程序员文章站 2023-12-14 21:46:34
先给大家展示下效果图: package com.lixu.circlemenu; import android.app.activity; impor...

先给大家展示下效果图:

基于Android实现转盘按钮代码

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实现转盘按钮代码的全部内容就到此结束了,希望能够帮助到大家。

上一篇:

下一篇: