For many developers, the cool UI effect is the most attractive, and many people are learning some of the more well-known UI libraries because of these cool effects. The premise of the cool effect is that you have to understand the custom view, as 90 of the Wang is naturally no exception. Especially for the early development of Wang, the custom view is mysterious and handsome, so Wang decided to delve into the custom view and related knowledge points.
Before we take a look at the original picture of the gods:
Remember it was the first snowfall of 2014, a little later than ever. Wang's colleague, uncle, is a senior developer who specializes in writing UI effects and is highly known in the field of development. Recently Uncle Yang has just released a good round menu, the menu of each item loop arrangement, and can rotate. Wang decided to emulate the effect of uncle, but for Wang this stage as long as the realization of the circular layout is good, the rotation part as the next version of the function, as a custom view practice.
After Google has customized view-related knowledge points, Wang has written this circular menu layout view, we explain step-by-step, the code is as follows:
Round menu public class Circlemenulayout extends ViewGroup {//circular diameter private int mradius;//default size of child item in the container private STA
Tic Final float radio_default_child_dimension = 1/4f;
The inner margin of the container, ignoring the PADDING property, such as the margin please use the variable private static final float radio_padding_layout = 1/12f;
The inner margin of the container, ignoring the Padding property, such as the margin, please use the variable private float mpadding;
Start angle of layout private double mstartangle = 0;
The text of the menu item private string[] mitemtexts;
menu item icon Private int[] Mitemimgs;
Number of menus private int mmenuitemcount;
Menu layout Resource ID private int mmenuitemlayoutid = R.layout.circle_menu_item;
MenuItem Click event Interface Private Onitemclicklistener Monmenuitemclicklistener;
Public Circlemenulayout (context, AttributeSet attrs) {Super (context, attrs);//Ignore padding setpadding (0, 0, 0, 0); }//Set menu entry icon and text public void setmenuitemiconsandtexts (int[] images, string[] texts) {if (images = null && text
s = = null) {throw new IllegalArgumentException ("menu item text and picture at least set first");} Mitemimgs = images;
mitemtexts = texts; Initialize Mmenucount mmenUitemcount = images = = null?
Texts.length:images.length; if (images!= null && texts!= null) {Mmenuitemcount = Math.min (Images.length, texts.length);}//Build menu item Buildmen
Uitems (); }//Build menu item private void Buildmenuitems () {////According to user-set parameters, initialize menu item for (int i = 0; i < Mmenuitemcount; i++) {View it
Emview = Inflatemenuview (i);
Initializes the menu item Initmenuitem (Itemview, i);
Add view to the container AddView (Itemview);
} Private View Inflatemenuview (final int childindex) {Layoutinflater minflater = Layoutinflater.from (GetContext ());
View Itemview = Minflater.inflate (Mmenuitemlayoutid, this, false); Itemview.setonclicklistener (New Onclicklistener () {@Override public void OnClick (View v) {if Monmenuitemclicklistener
!= null) {Monmenuitemclicklistener.onclick (V, Childindex);}}
});
return itemview; } private void Initmenuitem (View itemview, int childindex) {ImageView IV = (ImageView) itemview. Findviewbyid (R.id.id_cir
Cle_menu_item_image); TextView TV = (TextView) itemview. Findviewbyid (r.iD.id_circle_menu_item_text);
Iv.setvisibility (view.visible);
Iv.setimageresource (Mitemimgs[childindex]);
Tv.setvisibility (view.visible);
Tv.settext (Mitemtexts[childindex]);
}//Set MenuItem layout file, must call public void Setmenuitemlayoutid (int mmenuitemlayoutid) {before setmenuitemiconsandtexts
This.mmenuitemlayoutid = Mmenuitemlayoutid;
//Set MenuItem Click event Interface public void Setonitemclicklistener (Onitemclicklistener listener) {
This.monmenuitemclicklistener = listener; }//code omitted}
Wang's thinking is generally the case, first let the user through the Setmenuitemiconsandtexts function to the menu item icon and text passed in, according to these icons and text to build the item, the layout view of the item is stored by Mmenuitemlayoutid, This mmenuitemlayoutid defaults to Circle_menu_item.xml, the XML layout for a imageview displayed on top of a text control. In order to customize the menu items, Wang also added a Setmenuitemlayoutid function that allows users to set the layout of the menu items, hoping that the user can customize a variety of style menus. After the user has set up the relevant data for the menu item, Wang constructs, initializes, and adds the same number of menu items to the Round menu Circlemenulayout, based on the number of icons and text that the user has set in. Then add a Setonitemclicklistener function that sets the processing interface for the user to click on the menu item so that the Click event can be handled by the user.
After adding the menu items to the circlemenulayout is to measure and layout the menu items, we first look at the size of the code, as follows:
Sets the width of the layout and the Policy menu item is wide @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {//measuring its own dimensions meas
Uremyself (Widthmeasurespec, Heightmeasurespec);
Measurement menu item size measurechildviews (); } private void Measuremyself (int widthmeasurespec, int heightmeasurespec) {int reswidth = 0; int resheight = 0;
number, respectively obtaining the measuring mode and measuring value int width = measurespec.getsize (widthmeasurespec);
int widthmode = Measurespec.getmode (Widthmeasurespec);
int height = measurespec.getsize (heightmeasurespec);
int heightmode = Measurespec.getmode (Heightmeasurespec); If the width or height of the measurement mode is not the exact value if (Widthmode!= measurespec.exactly | | heightmode!= measurespec.exactly) {///main set to background image height Reswidth =
Getsuggestedminimumwidth (); If the background picture is not set, set to the default value of the screen width reswidth = Reswidth = = 0?
Getdefaultwidth (): reswidth;
Resheight = Getsuggestedminimumheight (); If the background picture is not set, set to the default value of the screen width resheight = Resheight = = 0?
Getdefaultwidth (): resheight; else {//If all are set to the exact value, take the decimal value directly; reswidth = Resheight = math.min (width, height);} setmeAsureddimension (Reswidth, resheight); private void Measurechildviews () {//get radius Mradius = Math.max (Getmeasuredwidth (), Getmeasuredheight ());//menu item Quantity F
inal int count = Getchildcount ();
menu item size int childsize = (int) (Mradius * radio_default_child_dimension);
menu item measurement mode int childmode = measurespec.exactly; Iterative measurements for (int i = 0; i < count; i++) {final View child = Getchildat (i); if (child.getvisibility () = = GONE) {Contin
Ue
//Calculate the menu item size, and set the mode to measure the item int makemeasurespec =-1;
Makemeasurespec = Measurespec.makemeasurespec (childsize, Childmode);
Child.measure (Makemeasurespec, Makemeasurespec);
} mpadding = Radio_padding_layout * Mradius; }
The
Code is simpler, measuring the size of the circlemenulayout first, and then measuring the size of each menu item. After the dimension is acquired, the layout is the step, which is the core of the whole round menu. The code is as follows:
Layout menu item position @Override protected void OnLayout (Boolean changed, int l, int t, int r, int b) {final int childcount =
Getchildcount ();
int left, top;
The size of the menu item int itemwidth = (int) (Mradius * radio_default_child_dimension);
According to the number of menu item, calculate the layout of the item occupies the angle float angledelay = 360/childcount; Traverse all menu items to set their position for (int i = 0; i < ChildCount; i++) {final View child = Getchildat (i); if (child.getvisibility () = =
GONE) {Continue}///menu item starting angle Mstartangle%= 360;
Calculates, the distance from the center point to the center of the menu item is float distancefromcenter = MRADIUS/2F-ITEMWIDTH/2-mpadding; Distancefromcenter Cosa the left coordinate of the menu item Center point = MRADIUS/2 + (int) math.round (Distancefromcenter * Math.Cos (math.to
Radians (Mstartangle)) *-1/2f * itemwidth); Distancefromcenter Sina is the ordinate top of menu item = MRADIUS/2 + (int) math.round (Distancefromcenter * Math.sin (Math.toradi
Ans (mstartangle)) *-1/2f * itemwidth);
Layout child View Child.layout (left, top, left + itemwidth, top + itemwidth); Stacked Size MSTartangle + = Angledelay; }
}
The OnLayout function looks slightly more complex, but it means that all menu items are laid out in the form of arcs. The entire circle is 360 degrees, if each menu item occupies an angle of 60 degrees, then the angle of the first menu item is 0~60, then the angle of the second menu item is 60~120, and so on, all menu items are arranged in a circular layout. First you calculate the left and top positions of each menu item, and the graphical representation of the formula is shown in the figure.
The small circle in the lower right corner of the picture is our menu item, then his left coordinate is MRADIUS/2 + tmp * COAs, and the top coordinate is MRADIUS/2 + tmp * sina. The TMP here is the distancefromcenter variable in our code. After this step, Wang's first version of the Round menu is complete.
Here we will integrate this round menu.
After you create a project, first add the Circle menu control in the layout XML, as follows:
<linearlayout xmlns:android= "http://schemas.android.com/apk/res/android"
xmlns:tools= "http:// Schemas.android.com/tools "
android:layout_width=" match_parent "
android:layout_height=" Match_parent "
android:background= "@drawable/bg"
android:gravity= "center"
android:orientation= "Horizontal" >
<com.dp.widgets.circlemenulayout
xmlns:android= "Http://schemas.android.com/apk/res/android"
Android:id= "@+id/id_menulayout"
android:layout_width= "wrap_content"
android:layout_height= "WRAP_" Content "
android:background=" @drawable/circle_bg "/>
</LinearLayout>
For better display, in the layout XML we have added a background image to the upper layer of the round menu and to the Round menu book. Then, set menu item data and click event in Mainactivity. The code looks like this:
public class Mainactivity extends activity {private circlemenulayout mcirclemenulayout;//Menu Label
Topic private string[] mitemtexts = new string[] {"Security Center", "special service", "Investment finance", "Transfer remittance", "My Account", "Credit Card"}; Menu icon Private int[] Mitemimgs = new int[] {r.drawable.home_mbank_1_normal, r.drawable.home_mbank_2_normal, R.drawable. Home_mbank_3_normal, R.drawable.home_mbank_4_normal, R.drawable.home_mbank_5_normal, R.drawable.home_mbank_6_
normal}; @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview (
R.layout.activity_main);
Initialize the round menu mcirclemenulayout = (circlemenulayout) Findviewbyid (r.id.id_menulayout);
Set menu data Item mcirclemenulayout.setmenuitemiconsandtexts (MITEMIMGS, mitemtexts); Set menu item Click event Mcirclemenulayout.setonitemclicklistener (New Onitemclicklistener () {@Override public void OnClick (View
view, int pos) {toast.maketext (Mainactivity.this, Mitemtexts[pos], Toast.length_short). Show (); }
}
The effect is as shown in the previous move diagram.
Wang triumphantly jumped out a word: cool! At the same time also for their ability to learn to be proud of the face is full of satisfaction and pride, feel himself again toward a senior engineer step closer.
"This is not a round menu written by Uncle Yang, does wang also download it?" "The whole preparation manager sees this UI effect and asks." Wang had to put the reason, the realization of the way to the director to listen to, Wang also specifically stressed the circlemenulayout customizable, through the Setmenuitemlayoutid function to set the menu item layout ID, so that the menu item UI effect can be customized by the user. The supervisor scanned the code of Wang and seemed to perceive something. So turned to find still immersed in the study of the Code of Uncle, and the realization of the simple introduction of Wang, foreign teacher in a glance at the code after the discovery of the problem lies.
"Wang Na, you just said that the user can set the UI effect of a menu item through the Setmenuitemlayoutid function. So the problem is, in your circlemenulayout, the default implementation of the Circle_menu_item.xml logic, such as loading the menu item layout will be through the Findviewbyid to find the layout of each child view, and data binding. For example, set the icon and text, but this is the specific implementation of this layout for circle_menu_item.xml. If the user sets the menu item layout to Other_menu_item.xml and each menu item is modified to be a button, then he must modify the code for the initialization menu item in Circlemenulayout. Because the layout changed, the type of view in the menu item also changed, and the data that the menus needed changed. For example, a menu item no longer needs an icon, just text. As a result, users need to modify the Circlemenulayout class once for each menu style, and the interface to set menu data needs to be changed. There is no customization, and it is a clear violation of the principle of opening and closing. Repeated changes to the circlemenulayout will inevitably introduce a variety of problems ... "Uncle Yang is really on the nail, profound ah!" Wang This just found the problem, so ask foreign uncle how to deal with the more appropriate teacher.
"You should use adapter, like the adapter in ListView, to get users to customize the layout, parsing, and data binding of menu items, and all you need to know is that each menu item is a view. This separates the changes through the adapter layer, and you rely only on adapter this abstraction. Each user can have a different implementation, you only need to implement the circular menu measurement, layout work can be. This allows you to embrace change, and customization is guaranteed. Of course, you can provide a default adapter, which is the menu implemented using your circle_menu_item.xml layout, so that users without custom requirements can use this default implementation. Wang nodded frequently and repeatedly said yes. "It was really something I didn't think about before, and it was really inadequate, and I'm going to do a good job of refactoring." "When Wang discovers the problem, he admits that he is deficient, and the two seniors who are so eager to learn will be accompanied by a refactoring code."
Under the guidance of two predecessors, after less than five minutes of reconstruction, Wang's circlemenulayout became the following.
Round Menu Public
class Circlemenulayout extends ViewGroup {
//field ellipsis
//set adapter public
void Setadapter ( ListAdapter madapter) {
this.madapter = madapter;
}
Build menu item
private void Buildmenuitems () {
////According to user-set parameters, initialize menu item for
(int i = 0; i < Madapter.getcount () ; i++) {
final View Itemview = Madapter.getview (i, NULL, this);
final int position = i;
Itemview.setonclicklistener (New Onclicklistener () {
@Override public
void OnClick (View v) {
if ( Monmenuitemclicklistener!= null) {
Monmenuitemclicklistener.onclick (itemview, position);
}}}
);
//Add view to Container
AddView (Itemview);
}
@Override
protected void Onattachedtowindow () {
if (madapter!= null) {
buildmenuitems ();
}
Super.onattachedtowindow ();
}
Measurement, layout code omitted
}
The circlemenulayout now removes the concrete work of parsing XML and initializing the menu item, adding a adapter, after the user sets the adapter, Call the adapter's GetCount function in the Onattachedtowindow function to get the number of menu items, then get each view through the GetView function, and then add the view of these menu items to the Circular menu. The Round menu layout is then laid out to a specific location.
Let's look at the form of using circlemenulayout now. First defines an entity class MenuItem to store menu item icons and text information, as follows:
Static class MenuItem {public
int imageid;
public String title;
Public MenuItem (String title, int resid) {
this.title = title;
imageID = Resid;
}
And then realize a adapter, the type of adapter is listadapter. We need to load the menu item XML, binding data, etc. in the GetView, the relevant code is as follows:
static class Circlemenuadapter extends Baseadapter {list<menuitem> mmenuitems; pu Blic circlemenuadapter (list<menuitem> menuitems) {mmenuitems = MenuItems;}//Load menu item layout, and initialize each menu @Override public V Iew GetView (final int position, View Convertview, ViewGroup parent) {Layoutinflater Minflater = Layoutinflater.from (paren
T.getcontext ());
View Itemview = Minflater.inflate (R.layout.circle_menu_item, parent, false);
Initmenuitem (Itemview, position);
return itemview;
}//Initialize menu item private void Initmenuitem (View itemview, int position) {//Get data item final MenuItem item = getitem (position);
ImageView IV = (ImageView) itemview. Findviewbyid (R.id.id_circle_menu_item_image);
TextView TV = (TextView) itemview. Findviewbyid (R.id.id_circle_menu_item_text);
Data binding iv.setimageresource (Item.imageid);
Tv.settext (Item.title); }//Omit code to get item count, etc.
This is consistent with our use of adapter in ListView, implementing functions such as GetView, GetCount, loading the layout files for each item in the GetView, and binding the data. The menu view is eventually returned, and the view is added to the circlemenulayout. The operation of this step was originally placed in the Circlemenulayout, is now independent, and through the adapter isolation. This separates the volatile parts from the adapter abstraction, and even if the user has thousands of menu item UI effects, it can be easily extended and implemented through adapter without having to modify the code in Circlemenulayout every time. The Circlemenulayout layout class is equivalent to providing a circular layout abstraction, and as to what each child view is, it does not need to be cared for. It's as simple as isolating change and embracing change through adapter.
"Originally ListView, Recyclerview through a adapter is this reason, through the adapter will be variable part of the independent to the user to deal with." The data and UI are decoupled through the observer mode, so that the view and the data are not dependent, and a single piece of data can be used for multiple UIs to handle the variability of the UI. I see! Wang finally summed up the way.
For example, when our product changes, we need to change the Circle menu to the normal ListView style, then we have to do is very simple, is the XML layout of the Circlemenulayout modified to ListView, Then set the adapter to ListView. The code is as follows:
public class Mainactivity extends activity {
private ListView mlistview;
list<menuitem> mmenuitems = new arraylist<menuitem> ();
@Override
protected void onCreate (Bundle savedinstancestate) {
super.oncreate (savedinstancestate);
Setcontentview (r.layout.activity_main);
Analog Data
mockmenuitems ();
Mlistview = (ListView) Findviewbyid (r.id.id_menulayout);
Set Adapter
mlistview.setadapter (New Circlemenuadapter (Mmenuitems));
Set Click event
mlistview.setonitemclicklistener (new Onitemclicklistener () {
@Override public
Void Onitemclick (adapterview<?> parent,
view view, int position, long id) {
toast.maketext ( Mainactivity.this,
mmenuitems.get (position). Title,
toast.length_short). Show ();
This completes the UI substitution, which is low cost and basically does not cause other errors. That's why we're using ListAdapter in circlemenulayout to be compatible with existing components such as ListView, GridView, and of course we don't have to redefine a adapter type again. Since then we can arbitrarily modify our menu item style, to ensure the flexibility of this component!! The effect of replacing with ListView is as follows:
"Go, I invite two predecessors to eat grilled fish go!" "Wang Circlemenulayout after the reconstruction of the deep harvest, in order to repay the director and foreign uncle's advice to invite dinner." "Then let's Go!" "The director is quick to agree, foreign Uncle Teacher also immediately answer, three people clean up the computer and then toward the downstairs of the Wushan grilled fish shop to go."
20.9 Summary
The classic implementation of adapter mode is to integrate incompatible interfaces so that they can cooperate well. But in the actual development, the adapter mode also has some flexible realization. For example, the isolation changes in ListView make the entire UI architecture more flexible and able to embrace change. Adapter mode is widely used in development, so it is very necessary to master adapter mode.
On the adapter mode of the actual combat of the construction of the Android round menu of Hong Yang group the relevant knowledge of CCB to introduce to everyone here, I hope to help you!