Android UI Design < 11 > Custom ViewGroup to create a universal off keyboard widget Imeobserverlayout

Source: Internet
Author: User
Tags gety

Reprint Please specify source:http://blog.csdn.net/llew2011/article/details/51598682

Our usual development always meet some of the needs of the wonderful, in order to achieve these needs we often racked our brains sometimes also tea does not think the rice is not fragrant, a bit exaggerated (*^__^*) ... One of my deepest impressions is the bold display of some words in a piece of text. It took a lot of effort, but fortunately, the problem finally solved, interested in children's boots can be seen:Android UI Design < six > use HTML tags, the implementation of TextView in the partial text to bold display .

Before the product has asked such a demand: the user entered the information after the request to click the Non-input box to hide the soft keyboard. At that time to see this demand feel no difficulty is more practical, so dizzy to achieve, but later the product said that as long as there is input box page All to follow this logic, the United States its name Yue user experience ... There were many pages with input boxes in the project, and if each page was written over logic, it would be a serious violation of the charm principle in the book "Refactoring, improving the design of existing code" (the charm principle is that if the same logic code is written more than three times, the refactoring should be considered). So it took a little time to get a general-purpose lightweight off-keyboard widget imeobserverlayout, which is what we're going to talk about today.

Before we start the code, let's take a look at the activity hierarchy and learn what the view structure is on the screen after activity starts, The easiest way to get a clear view of the activity's display hierarchy is by using the tool Hierarchyviewer provided by Google (which is located under the Tools folder in the SDK). Hierarchyviewer can not only display the interface view level of the currently running app, but also optimize our layout structure through the view level.

In order to use the Hierarchyviewer tool to view the hierarchy of the current app, let's start with a simple test that defines the layout file Activity_mian.xml as follows:

<framelayout 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 " >    <textview        android:layout_width= "wrap_content"        android:layout_height= "Wrap_content        " android:layout_gravity= "center"        android:text= "test hierarchy View"/></framelayout>
The layout file is very simple, the root node is framelayout, a textview is nested in the middle, and the TextView is centered. Then define the mainactivity with the following code:
public class Mainactivity extends Activity {@Overrideprotected void onCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview (R.layout.activity_main);}}
The code is simple and runs as follows:

After running the program we find Hierarchyviewer under the Tools folder of the SDK, double click to open it, and then run as follows:


When Hierarchyviewer is open, the tool lists all the programs that the current phone can display at the view level, and the currently running program is displayed in bold and black in the list. To find our program, double-click Open as shown:


Is our current mainactivity run the layout structure, the lower left side is the structure diagram, the right is the thumbnail and corresponding placement map, here no longer the use of the tool to explain, interested in the child boots can be self-check. According to the structure diagram, the root view of the current activity is the Dercorview under the Phonewindow class, which contains a linearlayout child view, and the sub-view LinearLayout contains three sub-views. One viewstub and two fragmelayout, the first view viewsub shows the status bar section, the second view framelayout contains a textview, which is used to display the caption, for the third view Framelayout, Its ID is content, which is the direct parent view of the view that we call the Setcontentview () method in activity to display for the current activity setting.

Once you understand the hierarchy of activity, consider starting with a hierarchy to implement a generic off-keyboard gizmo. We know that in the Android system events are passed in layers, that is, the event is first passed to the root view Decorview, then passed down sequentially and finally to the target view. If you add a custom viewgroup in the middle of the root view Decorview and its child view linearlayout, we can intercept the event in a custom ViewGroup to determine whether to turn off the soft keyboard.

Now that you want to add a custom viewgroup in the middle of Decorview and its sub-view linearlayout, we'll first get the decorview, from the structure of the activity above, we know the Setcontentview to invoke activity ( When content is set to activity, it is eventually added to the framelayout with the ID content, so you can get this framelayout based on the ID, and then loop up to find the parent until a view with no parent is found. Then this view is Decorview. This approach is feasible but not recommended, and Google engineers added a GetWindow () method to the activity when constructing the activity, which returns a Window object representing the Windows class, which is an abstract class. It has a method Getdecorview (), see the framework source of the child boots should be clear that the method returned is the root view decorview, so we use this way.

Now that we can get to the root view Decorview, the next step is to consider the features that our viewgroup should have. The first thing to do is to turn off the soft keyboard by tapping the area outside the edittext of the input box to know what EditText are in the current layout, so there is a collection in the custom viewgroup that holds all the input boxes in the current layout file EditText Second, at what time to find and save all the input boxes in the current layout edittext, and at what time to empty the saved input box edittext; again, when the finger taps the screen, you get the XY coordinates of the click, Determine whether the click Position falls in the input box EditText in order to determine if the soft keyboard is turned off according to the click coordinates.

Start implementing our ViewGroup with these questions, the code is as follows:

public class Imeobserverlayout extends Framelayout {private list<edittext> medittexts;public imeobserverlayout ( Context context) {super (context);} Public Imeobserverlayout (context context, AttributeSet Attrs) {Super (context, attrs);} Public Imeobserverlayout (context context, AttributeSet attrs, int defstyleattr) {Super (context, attrs, defstyleattr);} @SuppressLint ("Newapi") public imeobserverlayout (context context, AttributeSet attrs, int defstyleattr, int defstyleres ) {Super (context, Attrs, defstyleattr, defstyleres);} @Overrideprotected void Onattachedtowindow () {Super.onattachedtowindow (); Collectedittext (this);} @Overrideprotected void Ondetachedfromwindow () {clearedittext (); Super.ondetachedfromwindow ();} @Overridepublic boolean onintercepttouchevent (motionevent ev) {if (Motionevent.action_down = = Ev.getaction () & & Shouldhidesoftinput (EV)) {hidesoftinput ();} return super.onintercepttouchevent (EV);} private void Collectedittext (View child) {if (null = = medittexts) {medittexts = new Arraylist<edittext> ();} if (child instanceof ViewGroup) {final ViewGroup parent = (viewgroup) child;final int childCount = Parent.getchildcount (); f or (int i = 0; i < ChildCount; i++) {View Childview = Parent.getchildat (i); Collectedittext (Childview);}} else if (child instanceof EditText) {final EditText EditText = (EditText) child;if (!medittexts.contains (EditText)) { Medittexts.add (EditText);}}} private void Clearedittext () {if (null! = medittexts) {medittexts.clear (); medittexts = null;}} private void Hidesoftinput () {Final Context context = GetContext (). Getapplicationcontext (); Inputmethodmanager IMM = ( Inputmethodmanager) Context.getsystemservice (Context.input_method_service); Imm.hidesoftinputfromwindow ( Getwindowtoken (), 0);} Private Boolean shouldhidesoftinput (Motionevent ev) {if (null = = Medittexts | | medittexts.isempty ()) {return false;} Final int x = (int) ev.getx (), final int y = (int) ev.gety (); Rect r = new rect (); for (EditText edittext:medittexts) {Edittext.getglobalvisiblerect (Rif (R.contains (x, y)) {return false;}} return true;}}

Imeobserverlayout inherits the Framelayout and defines the attribute medittexts,medittexts is used to save all the input box EditText in the current page. Find all input boxes EditText time we have selected the Onattachedtowindow () method, when the view is added to the window, the subsequent method is called, so Imeobserverlayout overrides the Onattachedtowindow () Method and call the Collectedittext () method in the method, let's take a look at the method:

private void Collectedittext (View child) {if (null = = medittexts) {medittexts = new arraylist<edittext> ();} if (child instanceof ViewGroup) {final ViewGroup parent = (viewgroup) child;final int childCount = Parent.getchildcount (); f or (int i = 0; i < ChildCount; i++) {View Childview = Parent.getchildat (i); Collectedittext (Childview);}} else if (child instanceof EditText) {final EditText EditText = (EditText) child;if (!medittexts.contains (EditText)) { Medittexts.add (EditText);}}}
The Collectedittext () method first makes a non-null check on medittexts and then determines whether the view passed in is ViewGroup type, If the ViewGroup type iterates through each of its sub-view and calls the Collectedittext () method recursively, if the EditText type is passed in, it determines whether the edittext has been saved in the current collection if it is not saved.

After you save the input box EditText also consider the problem of emptying, to avoid a memory leak. So imeobserverlayout rewritten the Ondetachedfromwindow () method and then called the Clearedittext () method to clear all the edittext.

private void Clearedittext () {if (null! = medittexts) {medittexts.clear (); medittexts = null;}}

After saving the edittext is to judge the logic of hiding the soft keyboard, in order to get the click coordinates, rewrite the Onintercepttouchevent () method, as follows:

@Overridepublic boolean onintercepttouchevent (motionevent ev) {if (Motionevent.action_down = = Ev.getaction () & & Shouldhidesoftinput (EV)) {hidesoftinput ();} return super.onintercepttouchevent (EV);}
In the Onintercepttouchevent () method, the event is first judged, if it is the down event and Shouldhidesoftinput () returns True, the Hidesoftinput () method is called to hide the soft keyboard, Let's take a look at the Shouldhidesoftinput () method with the following code:
Private Boolean shouldhidesoftinput (Motionevent ev) {if (null = = Medittexts | | medittexts.isempty ()) {return false;} Final int x = (int) ev.getx (), final int y = (int) ev.gety (); Rect r = new Rect (), for (EditText edittext:medittexts) {edittext.getglobalvisiblerect (R); if (R.contains (x, y)) {return FA LSE;}} return true;}

The Shouldhidesoftinput () method first determines whether the medittexts is null or if it is saved with edittext, if NULL or null directly returns false to indicate that the soft keyboard is not required, otherwise loops through all the EditText , determines whether the click position is within the EditText area according to the XY coordinates of the click, or returns True if the click coordinates return false directly within the EditText area.

Now that our custom imeobserverlayout is ready, the next step is to add imeobserverlayout to the Decorview and its child view linearlayout, to make it easier to use this control, We need to implement the added logic.

Add logic to get the root view decorview with activity, so to pass in the current activity, the complete code looks like this:

Public final class Imeobserver {private Imeobserver () {}public static void Observer (final activity activity) {if (null = = activity) {return;} Final View root = Activity.getwindow (). Getdecorview (); if (root instanceof viewgroup) {final ViewGroup Decorview = (Viewgro UP) Root;if (Decorview.getchildcount () > 0) {final View child = Decorview.getchildat (0);d ecorview.removeallviews (); Layoutparams params = Child.getlayoutparams (); Imeobserverlayout observerlayout = new Imeobserverlayout ( Activity.getapplicationcontext ()); Observerlayout.addview (child, params); Layoutparams LP = new Layoutparams (layoutparams.match_parent, layoutparams.match_parent);d Ecorview.addview ( OBSERVERLAYOUT, LP);}}} private static class Imeobserverlayout extends Framelayout {private list<edittext> Medittexts;public Imeobserverlayout (Context context) {super (context);} Public Imeobserverlayout (context context, AttributeSet Attrs) {Super (context, attrs);} Public Imeobserverlayout (context context, AttributeSet attrs, int defSTYLEATTR) {Super (context, attrs, defstyleattr);} @SuppressLint ("Newapi") public imeobserverlayout (context context, AttributeSet attrs, int defstyleattr, int defstyleres ) {Super (context, Attrs, defstyleattr, defstyleres);} @Overrideprotected void Onattachedtowindow () {Super.onattachedtowindow (); Collectedittext (this);} @Overrideprotected void Ondetachedfromwindow () {clearedittext (); Super.ondetachedfromwindow ();} @Overridepublic boolean onintercepttouchevent (motionevent ev) {if (Motionevent.action_down = = Ev.getaction () & & Shouldhidesoftinput (EV)) {hidesoftinput ();} return super.onintercepttouchevent (EV);} private void Collectedittext (View child) {if (null = = medittexts) {medittexts = new arraylist<edittext> ();} if (child instanceof ViewGroup) {final ViewGroup parent = (viewgroup) child;final int childCount = Parent.getchildcount (); for (int i = 0; i < ChildCount; i++) {View Childview = Parent.getchildat (i); Collectedittext (Childview);}} else if (child instanceof EditText) {finalEditText EditText = (EditText) child;if (!medittexts.contains (EditText)) {Medittexts.add (EditText);}}} private void Clearedittext () {if (null! = medittexts) {medittexts.clear (); medittexts = null;}} private void Hidesoftinput () {Final Context context = GetContext (). Getapplicationcontext (); Inputmethodmanager IMM = ( Inputmethodmanager) Context.getsystemservice (Context.input_method_service); Imm.hidesoftinputfromwindow ( Getwindowtoken (), 0);} Private Boolean shouldhidesoftinput (Motionevent ev) {if (null = = Medittexts | | medittexts.isempty ()) {return false;} Final int x = (int) ev.getx (), final int y = (int) ev.gety (); Rect r = new Rect (), for (EditText edittext:medittexts) {Edittext.getglobalvisiblerect (R), if (R.contains (x, y)) {return F Alse;}} return true;}}}

We put imeobserverlayout in the form of internal static class into the Imeobserver, and set the imeobserverlayout for private, the purpose is not to let the outside world to do operation, etc. Then add a static method observer (activity activity) to Imeobserver, in which the imeobserverlayout is added to the root view Decorview and its child view linearlayout in the middle.

Now all ready, test to see the effect of it, modify the Mainactivity code as follows:

public class Mainactivity extends Activity {@Overrideprotected void onCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview (r.layout.activity_ime); Imeobserver.observer (this);}}
Mainactivity code does not need to change, just after the Setcontentview () method added Imeobserver.observer (this) line of code to implement the function of the closed input box, is not very lightweight and integration is convenient? (*^__^*) ...

We run the program, the effect is as follows:


Well, look at the effect feels good, the control itself does not have any technical content, it is required to be familiar with the level structure of activity, and then clear the event delivery mechanism, and finally can determine the click position according to the coordinates to determine whether to turn off the soft keyboard.

OK, custom viewgroup, build your own universal off soft keyboard control Here's the point, thanks for watching ...






Android UI Design < 11 > Custom ViewGroup to create a universal off keyboard widget Imeobserverlayout

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.