Custom navigation menu for Android Development

Source: Internet
Author: User
Tags xml attribute

Custom navigation menu for Android Development
Nowadays, there are many solutions to implement the navigation function. For example: 1. Use the Toolbar + Fragment navigation that comes with 3.0 +. 2. Use Tabhost to implement navigation. When I was a beginner, I only used these two solutions to implement navigation. However, both solutions have an obvious drawback: the navigation location is too fixed. For example, a Toolbar can only be located in the title bar (ps: skipped by the source code modification ). There is also Tabhost. Although custom Tabhost is more flexible than directly inheriting TabActivity, there is no option to switch the animation (ps: Maybe I did not find it ). Sometimes, we just want to paste a navigation bar in the corner of a screen to switch the navigation bar and set the attributes. At this time, both Toolbar and Tabhost are a little useful, with a sense of balance and insufficient strength. As shown in the following figure: Recently, the project needs this information, so I checked some information. The principle of discovery is actually quite simple. For example, you can use the Button or TextView Button for the preceding tabs. You can simply respond to the click. The following ImageView is used to switch the animation. For example, if tab1 is used by default and tab3 is clicked, the following ImageView will be moved from tab1 to tab3 and stay. After understanding the principles, the next step is the specific implementation. Generally, there are two ways to implement such requirements: Using xml to implement dynamic java code. Separation of the Xml interface and java code control is a highlight of Android development and a stepping stone for countless entry books. However, this implementation has many limitations: today, this project has three tabs, there will be four tabs for tomorrow's project. At this time, we need to modify the xml and not to mention it, but also some underlying implementations, such as compressing the width of the ImageView. For portability and scalability, I chose java code implementation to implement subClass LinearLayout directly. I only perform some basic operations. You can add your own operations in my code, such as adding selector to each tab and adding Event Callback. First, my most streamlined implementation: the movement in the middle has an animated effect. It is too stiff to appear wherever it is not directly clicked. Next we will explain the specific implementation process: subclass-based LinearLayout. Of course, you can also subclass other viewgroups for personal interests. Public class CustomMenu extends LinearLayout implements OnClickListener declares the custom xml Attribute in the attrs. xml file <? Xml version = "1.0" encoding = "UTF-8"?> <Resources> <declare-styleable name = "CustomMenu"> <attr name = "buttonNumber" format = "integer"/> <attr name = "indexbitmap" format = "reference "/> <attr name = "buttonHeight" format = "dimension"/> </declare-styleable> </resources> where buttonNumber: the number of tabs in the navigation indexbitmap: The moving image, that is, the following horizontal line buttonHeight: the height of the navigation to add a layout in the xml layout file, layout_width and layout_height can be freely used by match_parent, wrap_content, or dp <LinearLayout xmlns: android = "Http://schemas.android.com/apk/res/android" xmlns: custommenu = "http://schemas.android.com/apk/res/com.example.fragmentdemo" android: layout_width = "match_parent" android: layout_height = "match_parent" android: orientation = "vertical"> <TextView android: layout_width = "match_parent" android: layout_height = "30dp" android: text = "@ string/hello_world"/> <com. example. fragmentdemo. fragmentmenu. customMenu androi D: layout_width = "match_parent" android: layout_height = "0dp" android: layout_weight = "1" mmmmenu: buttonNumber = "5" custommenu: buttonHeight = "40dp" custommenu: indexbitmap = "@ drawable/a"> </com. example. fragmentdemo. fragmentmenu. customMenu> <TextView android: layout_width = "match_parent" android: layout_height = "wrap_content" android: text = "@ string/hello_world"/> </LinearLayout> to highlight randomness, two textviews, la You can set yout_width and layout_height to match_parent, wrap_content, or 30dp. In the xml Attribute, I set the number of navigation bars to 5 and the height of the navigation bar to 40dp, the mobile image of the navigation is drawable. in java code, first read the custom xml Attribute Value private void readXML (Context context, AttributeSet attr) {TypedArray a = context. obtainStyledAttributes (attr, R. styleable. customMenu); // Number of read buttons buttonNumber =. getInt (R. styleable. customMenu_buttonNumber, 4); // The height of the read button buttonHeight = (int). getDimension (R. styleable. customMenu_buttonHeight, 30); // read the image int bitmapID =. getReso UrceId (R. styleable. customMenu_indexbitmap, R. drawable. a); bitmap = BitmapFactory. decodeResource (getResources (), bitmapID); bitmap_width = bitmap. getWidth ();. recycle ();} The comment has been clearly written. It is used to read custom attributes in xml. Note that buttonNumber, buttonHeight, bitmap, and bitmap_width are all member attributes. The number of tabs is limited by the buttonNumber, and the height of the tab is also limited by the buttonHeight. // SetOrientation (LinearLayout. VERTICAL); // Add a horizontal LinearLayout with the height set to LayoutParams p = new LayoutParams (LayoutParams. MATCH_PARENT, buttonHeight); LinearLayout linearLayout = new LinearLayout (context); linearLayout. setOrientation (LinearLayout. HORIZONTAL); linearLayout. setPadding (0, 0, 0, 0); linearLayout. setGravity (Gravity. CENTER); addView (linearLayout, p); // Add a specified Butt to this horizontal LinearLayout On LayoutParams btn_p = new LayoutParams (LayoutParams. MATCH_PARENT, buttonHeight, 1); for (int I = 0; I <buttonNumber; I ++) {Button button = new Button (context); button. setText ("button" + I); button. setTextSize (15); button. setBackgroundColor (getResources (). getColor (R. color. defaultColor); button. setId (ID + I); button. setOnClickListener (this); // Add to container button_container.add (button); // Add to layout linearLayout. addView (Button, btn_p);} Add a horizontal LinearLayout to add a tab. The height is the value entered by the user. Then, add the user-specified number of tabs (buttons) and set the weight (weight) is 1. Here I give the text and background color of the Button to the default value. You can expand it in xml or expose the method in the Code for user settings. Here is an ID. I gave the default value private static final int ID = 0xcc33cc. This is to differentiate onClick events. You can select the method by yourself. However, it is advantageous to use ID here, I will introduce it later. Add ImageView, which is not processed at the moment, because Bitmap dynamically adjusts imageView = new ImageView (context) because of the tab width; LayoutParams iv_p = new LayoutParams (LayoutParams. WRAP_CONTENT, LayoutParams. WRAP_CONTENT); iv_p.setMargins (0, 5, 0, 0); addView (imageView, iv_p); only an ImageView is placed here. The specific content will be set later, because the content is dynamic, the width and height cannot be determined during the constructor. In the onMearsure method, obtain the width and height of the View protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {super. onMeasure (widthMeasureSpec, heightMeasureSpec); // only execute this method once if (width = 0 | height = 0) {// obtain its own height and height width = MeasureSpec. getSize (widthMeasureSpec); height = MeasureSpec. getSize (heightMeasureSpec); // perform other initialization initial () ;}all know that the onMeasure method determines the control size based on the input parameters. In this method, the Dynamic Scaling of controls and the scaling of sub-controls are generally implemented. Here, I simply get the width and height of the control. Both Width and height are member variables. The if statement is used here because this method will be executed twice by default, probably because it will be drawn once as ViewGroup at the beginning, and will be drawn again after filling the child control. The details are not clear, you can check other information. In this example, if is used only once. Then, perform the remaining initialization in the initial () method. Perform some initialization operations // if the image width is greater than the button width, process the image if (bitmap_width> width/buttonNumber) {// narrow down the image bitmap = dealBitmap (bitmap, (float) (width)/buttonNumber/bitmap_width);} private Bitmap dealBitmap (Bitmap bitmap, float bili) {Matrix matrix = new Matrix (); matrix. postScale (bili, bili); // Bitmap resizeBmp = Bitmap. createBitmap (bitmap, 0, 0, bitmap. getWidth (), bitmap. getHeight (), matrix, true); return resi ZeBmp;} if the image width is greater than the width of each tab, scale the image to the same width as tab by default. You can define the scaling range by yourself. You can even expose the callback interface to external settings. // Set the offset value imageView_offset = (width/buttonNumber-bitmap_width)/2; // set the image imageView. setImageBitmap (bitmap); // initialize the image position initialImageViewOffset (); set the offset value. This imageView_offset is also a member variable. The purpose is to place the ImageView in the middle of the tab. The principle is similar: Set bitmap, because the width and height of bitmap are determined at this time. Call the initialImageViewOffset () method to set the offset value to private void initialImageViewOffset () {// if the offset value is greater than 0, move the image if (imageView_offset> 0) {Matrix matrix = new Matrix (); matrix. postTranslate (imageView_offset, 0); imageView. setImageMatrix (matrix) ;}} here, the offset value is greater than 0, because as mentioned above, if the bitmap width is greater than the tab width, it needs to be scaled to the same size as the tab, at this time, offset is equal to 0, which avoids useless work. Add and click the event public void onClick (View v) {// move from the current item to the clicked item moveImageView (cur_index, v. getId ()-ID); // value the current item cur_index = v. getId ()-ID;} Here we can see the advantages of using id to differentiate tabs. For convenience, first paste the moveImageView code private void moveImageView (int start, int end) {// The distance to be moved int length = (2 * imageView_offset + bitmap_width) * (end-start); // the initial position. The default ImageView is located at the imageView_offset to the left. Int offset = (2 * imageView_offset + bitmap_width) * start; Animation animation = new TranslateAnimation (offset, offset + length, 0, 0); // After the Animation ends, view stays at the end of the animation. setFillAfter (true); animation. setDuration (300); imageView. startAnimation (animation);} start indicates the current tab number, which starts from 0, such as tab0, tab1, and tab2. End refers to the number of the tab you click. For example, if tab3 is clicked at the beginning, start = 0 and end = 3. Then I clicked tab2 again, so start = 3 and end = 2.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.