First, the preface
Android implementation of the satellite menu is also called the Arc menu, the main work to do is as follows:
1. The processing of animation
2. Custom ViewGroup to implement the satellite menu view
(1) Custom properties
A. Defining properties in Attrs.xml
B. Using custom attributes in a layout
C. Reading custom attributes from View
a layout file in a customization
(2) onMeasure
measuring child
is the main button and the menu item
(3) onLayout
layout child
is the layout of the main button and menu items
(4) Set the selection animation of the main button
A. menuItem
add a translation animation and a rotational animation to a menu item
B. Implementing menuItem
The Click Animation of the menu item
Screenshot of satellite menu effect:
Second, realize
The above describes the principle and effect diagram, the following to see the implementation of the Satellite menu class:
1. The implementation of the layout file
<relativelayout xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:tools= "http:// Schemas.android.com/tools "xmlns:xcskin=" Http://schemas.android.com/apk/res/com.xc.xcskin "android:id=" @+id/ Container "android:layout_width=" match_parent "android:layout_height=" Match_parent "> < Com.xc.xcskin.view.XCArcMenuView android:id= "@+id/arcmenu" android:layout_width= "150DP" android:layout_height= " 150DP "android:layout_alignparentbottom=" true "android:layout_alignparentleft=" true "xcskin:position=" Left_bottom "xcskin:radius=" 120DP "> <relativelayout android:layout_width=" wrap_content "android:layout_height=" wrap _content "android:background=" @drawable/composer_button "> <imageview android:id=" @+id/id_button "and Roid:layout_width= "Wrap_content" android:layout_height= "Wrap_content" android:layout_centerinparent= "true" and
roid:src= "@drawable/composer_icn_plus"/> </RelativeLayout> <imageview Android:id= "@+id/id_button" android:layout_width= "wrap_content" android:layout_height= "Wrap_content" Android : src= "@drawable/composer_camera" android:tag= "Camera"/> <imageview android:id= "@+id/id_button" Androi D:layout_width= "Wrap_content" android:layout_height= "wrap_content" android:src= "@drawable/composer_music" Andr oid:tag= "Music"/> <imageview android:id= "@+id/id_button" android:layout_width= "Wrap_content" Android:
layout_height= "Wrap_content" android:src= "@drawable/composer_place" android:tag= "place"/> <imageview Android:id= "@+id/id_button" android:layout_width= "wrap_content" android:layout_height= "Wrap_content" android:s rc= "@drawable/composer_sleep" android:tag= "Sleep"/> <imageview android:id= "@+id/id_button" Android:la Yout_width= "Wrap_content" android:layout_height= "wrap_content" android:src= "@drawable/composer_thought" Androi
d:tag= "thought"/><imageview android:id= "@+id/id_button" android:layout_width= wrap_content "android:layout_height=" Wrap_cont
Ent "android:src=" @drawable/composer_with "android:tag=" with "/> </com.xc.xcskin.view.XCArcMenuView> <com.xc.xcskin.view.xcarcmenuview android:id= "@+id/arcmenu2" android:layout_width= "Wrap_content" Android:
layout_height= "Wrap_content" android:layout_alignparentbottom= "true" android:layout_alignparentright= "true"
xcskin:position= "Right_bottom" xcskin:radius= "150DP" > <relativelayout android:layout_width= "wrap_content" android:layout_height= "Wrap_content" android:background= "@drawable/composer_button" > <imageview androi D:id= "@+id/id_button" android:layout_width= "wrap_content" android:layout_height= "Wrap_content" Android:layout_ Centerinparent= "true" android:src= "@drawable/composer_icn_plus"/> </RelativeLayout> <imageview an Droid:id= "@+id/id_button" Android:laYout_width= "Wrap_content" android:layout_height= "wrap_content" android:src= "@drawable/composer_camera" Android : tag= "Camera"/> <imageview android:id= "@+id/id_button" android:layout_width= "Wrap_content" Android:la yout_height= "Wrap_content" android:src= "@drawable/composer_music" android:tag= "Music"/> <imageview an Droid:id= "@+id/id_button" android:layout_width= "wrap_content" android:layout_height= "Wrap_content" android:src = "@drawable/composer_place" android:tag= "place"/> <imageview android:id= "@+id/id_button" Android:layo Ut_width= "Wrap_content" android:layout_height= "wrap_content" android:src= "@drawable/composer_sleep" Android:ta g= "Sleep"/> <imageview android:id= "@+id/id_button" android:layout_width= "Wrap_content" android:layout _height= "Wrap_content" android:src= "@drawable/composer_thought" android:tag= "thought"/> <imageview an Droid:id= "@+id/id_button"Android:layout_width=" wrap_content "android:layout_height=" wrap_content "android:src=" @drawable/composer_wit H "android:tag=" with "/> </com.xc.xcskin.view.XCArcMenuView> </RelativeLayout>
2. Implementation of the Satellite menu class
Package Com.xc.xcskin.view;
Import COM.XC.XCSKIN.R;
Import Android.content.Context;
Import Android.content.res.TypedArray;
Import Android.util.AttributeSet;
Import Android.util.Log;
Import Android.util.TypedValue;
Import Android.view.View;
Import Android.view.View.OnClickListener;
Import Android.view.ViewGroup;
Import android.view.animation.AlphaAnimation;
Import android.view.animation.Animation;
Import Android.view.animation.Animation.AnimationListener;
Import Android.view.animation.AnimationSet;
Import android.view.animation.RotateAnimation;
Import android.view.animation.ScaleAnimation;
Import android.view.animation.TranslateAnimation; /** * Satellite Menu View * @author caizhiming * * */public class Xcarcmenuview extends ViewGroup implements onclicklistener{p
rivate static final int pos_left_top = 0;
private static final int pos_left_bottom = 1;
private static final int pos_right_top = 2;
private static final int pos_right_bottom = 3; Private Position mposition = Position.right_BOTTOM;
private int Mradius;
Private Status mstatus = Status.close;
Main Course single button private View Mcbutton;
Private Onmenuitemclicklistener Monmenuitemclicklistener; /** * Menu Status Enumeration class * @author caizhiming * * */public enum status{open,close}/** * Menu Position Enumeration class * @author Caizhi Ming */public enum position{Left_top,left_bottom, Right_top,right_bottom}/** * Click the callback interface for the submenu item * @author
caizhiming * */public interface Onmenuitemclicklistener {void OnClick (view view, int pos); } public void Setonmenuitemclicklistener (Onmenuitemclicklistener onmenuitemclicklistener) {This.monmenuitemclickl
Istener = Onmenuitemclicklistener;
The public Xcarcmenuview {This (context, NULL); TODO auto-generated Constructor stub} public Xcarcmenuview (context, AttributeSet attrs) {The context, at
TRS, 0); TODO auto-generated Constructor stub} public Xcarcmenuview (context, AttributeSet attrs, int defstyle) {su Per (contExt, attrs, defstyle);
TODO auto-generated constructor stub//Get custom attribute TypedArray a = Context.gettheme (). Obtainstyledattributes (Attrs,
r.styleable.xcarcmenuview,defstyle,0);
int pos = A.getint (r.styleable.xcarcmenuview_position, Pos_right_bottom);
Switch (POS) {case pos_left_top:mposition = position.left_top;
Break
Case pos_left_bottom:mposition = Position.left_bottom;
Break
Case pos_right_top:mposition = position.right_top;
Break
Case pos_right_bottom:mposition = Position.right_bottom;
Break } Mradius = (int) a.getdimension (R.styleable.xcarcmenuview_radius, (int) typedvalue.applydimension (TypedValue.COMPL
Ex_unit_dip, Getresources (), Getdisplaymetrics ()));
LOG.V ("Czm", "mposition =" + Mposition + ", Mradius =" +mradius);
A.recycle (); @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {//TODO auto-generated method Stu
b int count = Getchildcount (); For (int i = 0; I < count;
i + +) {Measurechild (Getchildat (i), Widthmeasurespec, Heightmeasurespec);
} super.onmeasure (Widthmeasurespec, Heightmeasurespec);
@Override protected void OnLayout (Boolean changed, int l, int t, int r, int b) {//TODO auto-generated method stub
if (changed) {Layoutcbutton ();
Layoutmenuitems (); }/** * Layout main Menu item */private void Layoutcbutton () {//TODO auto-generated method Stub Mcbutton = Getchildat (
0);
Mcbutton.setonclicklistener (this);
int l = 0;
int t = 0;
int width = mcbutton.getmeasuredwidth ();
int height = mcbutton.getmeasuredheight ();
Switch (mposition) {case left_top:l = 0;
t = 0;
Break
Case left_bottom:l = 0;
t = getmeasuredheight ()-height;
Break
Case right_top:l = Getmeasuredwidth ()-width;
t = 0;
Break
Case right_bottom:l = Getmeasuredwidth ()-width;
t = getmeasuredheight ()-height;
Break
Default:break; } Mcbutton.layoUT (l, T, L + width, t + height); }/** * Layout menu item */private void Layoutmenuitems () {//TODO auto-generated method Stub int count = Getchildcount ()
;
for (int i = 0; i < count-1. i++) {View child = Getchildat (i + 1);
int L = (int) (Mradius * Math.sin (MATH.PI/2/(count-2) * i));
int t = (int) (Mradius * Math.Cos (MATH.PI/2/(count-2) * i));
int width = child.getmeasuredwidth ();
int height = child.getmeasuredheight (); If the menu position is at the bottom left, lower right if (mposition = Position.left_bottom | | | mposition = = position.right_bottom) {t = Getmeasuredhe
Ight ()-height-t; //upper Right, bottom right if (mposition = Position.right_top | | | mposition = = position.right_bottom) {L = getmeasuredwidth ()-
Width-l;
} child.layout (L, T, L + width, t + height);
Child.setvisibility (View.gone); @Override public void OnClick (View v) {//TODO auto-generated method Stub Mcbutton = Findviewbyid (R.id.id_butt
ON);
Rotatecbutton (v,0,360,300); TogglemenU (300); /** * Toggle Menu */public void Togglemenu (int duration) {//TODO auto-generated Method Stub//Add translation animation and rotation to MenuItem
Draw int count = Getchildcount ();
for (int i = 0; i < count-1 i++) {final View Childview = getchildat (i + 1);
Childview.setvisibility (view.visible);
End 0, 0//start int cl = (int) (Mradius * Math.sin (MATH.PI/2/(count-2) * i));
int ct = (int) (Mradius * Math.Cos (MATH.PI/2/(count-2) * i));
int xflag = 1;
int yflag = 1;
if (mposition = = Position.left_top | | mposition = = position.left_bottom) {Xflag =-1;
} if (mposition = = Position.left_top | | mposition = = position.right_top) {Yflag =-1;
} animationset Animset = new Animationset (true);
Animation Trananim = null;
To open if (mstatus = = status.close) {Trananim = new translateanimation (Xflag * cl, 0, Yflag * ct, 0);
Childview.setclickable (TRUE);
Childview.setfocusable (TRUE);
} else To close {Trananim = new Translateanimation (0, Xflag * cl, 0, Yflag * ct);
Childview.setclickable (FALSE);
Childview.setfocusable (FALSE);
} trananim.setfillafter (True);
Trananim.setduration (duration);
Trananim.setstartoffset ((i *)/count); Trananim.setanimationlistener (New Animationlistener () {@Override public void Onanimationstart (Animation anima tion) {} @Override public void Onanimationrepeat (Animation Animation) {} @Override P ublic void Onanimationend (Animation Animation) {if (Mstatus = = status.close) {Childview.setvisibilit
Y (View.gone);
}
}
}); Rotary animation Rotateanimation Rotateanim = new Rotateanimation (0, 720, animation.relative_to_self, 0.5f, Animation.
Relative_to_self, 0.5f);
Rotateanim.setduration (duration);
Rotateanim.setfillafter (TRUE);
Animset.addanimation (Rotateanim);
Animset.addanimation (Trananim); Childview.startanimatIon (Animset);
Final int pos = i + 1; Childview.setonclicklistener (New Onclicklistener () {@Override public void OnClick (View v) {if monme
Nuitemclicklistener!= null) Monmenuitemclicklistener.onclick (Childview, POS);
Menuitemanim (POS-1);
Changestatus ();
}
});
//Toggle Menu Status Changestatus (); /** * Select Main Menu button */private void Rotatecbutton (View V, float start, float end, int duration) {//TODO auto-g enerated method Stub Rotateanimation anim = new Rotateanimation (start, End, Animation.relative_to_self, 0.5f, Animat Ion.
Relative_to_self, 0.5f);
Anim.setduration (duration);
Anim.setfillafter (TRUE);
V.startanimation (ANIM); /** * Add MenuItem Click Animation * */private void Menuitemanim (int pos) {for (int i = 0; i < Getchildcount ()-1;
i++) {View Childview = getchildat (i + 1);
if (i = = pos) {childview.startanimation (Scalebiganim (300)); else {childview.startanimation(Scalesmallanim (300));
} childview.setclickable (FALSE);
Childview.setfocusable (FALSE); }/** * Set smaller and more transparent animation for the currently clicked Item * @param duration * @return/private Animation scalesmallanim (int duratio
N) {Animationset animationset = new Animationset (true); Scaleanimation Scaleanim = new Scaleanimation (1.0f, 0.0f, 1.0f, 0.0f, Animation.relative_to_self, 0.5f, Animation.rela
Tive_to_self, 0.5f);
Alphaanimation Alphaanim = new Alphaanimation (1f, 0.0f);
Animationset.addanimation (Scaleanim);
Animationset.addanimation (Alphaanim);
Animationset.setduration (duration);
Animationset.setfillafter (TRUE);
return animationset; /** * For the current click of the item to set a larger and less transparent animation/private Animation Scalebiganim (int duration) {Animationset Animationset = NE
W Animationset (True); Scaleanimation Scaleanim = new Scaleanimation (1.0f, 4.0f, 1.0f, 4.0f, Animation.relative_to_self, 0.5f, Animation.rela
Tive_to_self, 0.5f); Alphaanimation Alphaanim = new ALPHaanimation (1f, 0.0f);
Animationset.addanimation (Scaleanim);
Animationset.addanimation (Alphaanim);
Animationset.setduration (duration);
Animationset.setfillafter (TRUE);
return animationset; /** * Toggle Menu state */private void Changestatus () {mstatus = (Mstatus = = Status.close?
Status.OPEN:Status.CLOSE);
/** * is in the expanded state * @return * * public boolean IsOpen () {return mstatus = = Status.open; }
}
3. Using the Satellite menu class
package Com.xc.xcskin;
Import android.app.Activity;
Import Android.os.Bundle;
Import Android.view.View;
Import Android.widget.Toast;
Import Com.xc.xcskin.view.XCArcMenuView;
Import Com.xc.xcskin.view.XCArcMenuView.OnMenuItemClickListener;
Import Com.xc.xcskin.view.XCGuaguakaView;
Import Com.xc.xcskin.view.XCGuaguakaView.OnCompleteListener; /** * Use and test the custom Satellite menu View * @author caizhiming * * */public class Xcarcmenuviewdemo extends activity{@Override Protec
Ted void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
Setcontentview (R.layout.xc_arcmenu_view_demo);
Xcarcmenuview view = (Xcarcmenuview) Findviewbyid (R.id.arcmenu); View.setonmenuitemclicklistener (New Onmenuitemclicklistener () {@Override public void OnClick (view view, int pos
{//TODO auto-generated method Stub String tag = (string) view.gettag ();
Toast.maketext (xcarcmenuviewdemo.this, Tag, Toast.length_short). Show ();
}
}); }
}
Third, summary
Android implementation of the customized satellite menu (curved menu) content to this is basically over, interested friends can start to operate, only their own practice to a deeper understanding, I hope this article can help.