Custom ViewGroup of the Android UI design series to create a generic close keyboard widget Imeobserverlayout (9) _android

Source: Internet
Author: User
Tags gety html tags static class

Reprint Please indicate the source: http://blog.csdn.net/llew2011/article/details/51598682
We usually meet some wonderful needs in the development, In order to achieve these needs, we often racked our brains and sometimes the food is not fragrant, a bit exaggerated (*^__^*) ... One of my deepest impressions is the need to show some words in bold text. At that time a lot of effort, but fortunately, the problem is finally resolved, interested in child boots can look at: Android UI design < six > use HTML tags, to achieve in the TextView part of the text in bold display.
before the product has raised such a requirement: the user input after the information required to click the Non-input box to hide the soft keyboard. At that time to see this demand feel no difficulty is also more practical, so dizzy is the realization of the faint, but then the product side said as long as there are input box page All to follow this logic, the United States its name Yue user experience ... There were a lot of pages with input boxes in the project, if every page is written logically, this is a serious violation of the Shine principle of refactoring, improving the design of existing code (Shine principle says that if the same logical code is written more than three times, consider refactoring). So it took a little time to get a generic lightweight keyboard-closing widget imeobserverlayout, and that's what we're going to talk about today.
Before we begin to explain the code, let's take a look at the level diagram of the activity, and learn what the view structure is on the screen after the activity starts, The easiest way to get a clear view of the activity's display hierarchy is to use the tools Google has provided us hierarchyviewer (the tool is located under the Tools folder of 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 hierarchy.
To use the Hierarchyviewer tool to view the hierarchy of the current app, let's do a simple test, define the layout file Activity_mian.xml, the code is 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-level View"/>

</FrameLayout>

The layout file is simple, the root node is framelayout, a textview is nested in the middle, and the TextView is centered. Then define the Mainactivity code as follows:

public class Mainactivity extends activity {

 @Override
 protected void onCreate (Bundle savedinstancestate) { C14/>super.oncreate (savedinstancestate);
 Setcontentview (R.layout.activity_main);
 }



The code is simple, and the running effect diagram looks like this:

After running the program, we go to the SDK Tools folder to find Hierarchyviewer, double-click to open, after the operation screenshot as follows:


Hierarchyviewer opens, the tool lists all the programs that the current phone can display at the view level, and the currently running programs are displayed in bold and black in the list. Find our program, double-click Open, as shown in the following figure:


The image above is our current mainactivity runtime layout structure, the lower left side is the structure diagram, the right side is the thumbnail and corresponding display location map, here no longer the specific use of tools to explain, interested in child boots can be consulted. According to the chart, the root view of the current activity is the Dercorview under the Phonewindow class, which contains a linearlayout child view, and the child View LinearLayout contains three child views. One viewstub and two fragmelayout, the first view viewsub displays the status bar section, and the second view framelayout contains a textview that is used to display the caption, and for the third view Framelayout, Its ID is content, which is the direct parent view that we call the Setcontentview () method in the activity to set the view view that is displayed for the current activity.

Once you understand the hierarchy of the activity, consider implementing a generic keyboard-close control from a hierarchical structure. We know that in the Android system events are passed in layers, that is, the event is first passed to the root view Decorview, which is then passed down and eventually uploaded to the target view. If you add a custom viewgroup to 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 child view LinearLayout, you first get Decorview, and from the structure of the activity above, we know the setcontentview that invokes the activity ( When the content is set to the activity, it is eventually added to the framelayout with the content of the ID, so you can get this framelayout based on the ID, and then loop to the parent until you find a view with no parent. So 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 (), looked at the framework source of child boots should be clear that the method returns is the root view decorview, so we use this approach.

Now you can get to the root view Decorview, and then consider the functionality that our viewgroup should have. The first thing to achieve is to click on the area outside the input box edittext to close the soft keyboard to know what is in the current layout of the EditText, so the custom ViewGroup to have a collection, which is used to save 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 clicks on the screen, you can get the XY coordinates of the click, According to the click coordinates to determine whether the click Position falls in the input box edittext to decide whether to close the soft keyboard.

With the above questions to start implementing our ViewGroup, the code is as follows:

public class Imeobserverlayout extends Framelayout {private list<edittext> medittexts;
 Public Imeobserverlayout {Super (context);
 Public Imeobserverlayout (context, AttributeSet attrs) {Super (context, attrs); Imeobserverlayout (context, AttributeSet attrs, int defstyleattr) {Super (context, Attrs, defstyleattr
 ); @SuppressLint ("Newapi") public imeobserverlayout (context, AttributeSet attrs, int defstyleattr, int defstyle
 Res) {Super (context, Attrs, defstyleattr, defstyleres);
 } @Override protected void Onattachedtowindow () {Super.onattachedtowindow ();
 Collectedittext (this);
 } @Override protected void Ondetachedfromwindow () {clearedittext ();
 Super.ondetachedfromwindow (); @Override public 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) {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 = 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 false;
 } return true; 

 }
}

Imeobserverlayout inherits Framelayout and defines the properties medittexts,medittexts to hold all the input boxes edittext the current page. Find all input box EditText we selected the Onattachedtowindow () method, and when the view is added to the window the latter method is invoked, so imeobserverlayout overrides Onattachedtowindow () Method and call the Collectedittext () method in the method, let's 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 ();
 for (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 checksum of medittexts, and then it determines whether the passed in view is a viewgroup type. If the ViewGroup type loops over each of its child view and recursively calls the Collectedittext () method, if the EditText type is passed in, it determines whether the edittext is already saved in the current collection, and if it is not saved, it is added.
After saving the input box EditText also consider the problem of emptying, to avoid memory leaks. So imeobserverlayout again rewrote the Ondetachedfromwindow () method and then called the Clearedittext () method to empty all 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:

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

The event is judged first in the Onintercepttouchevent () method, and if the Down event and Shouldhidesoftinput () returns True, the Hidesoftinput () method is invoked 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
  false;
 }
 }
 return true;
}

The Shouldhidesoftinput () method first determines whether the medittexts is null or if the edittext is saved, if NULL or NULL, the direct return false means that you do not need to close the soft keyboard, otherwise loop through all the EditText , according to the click of XY coordinates to determine whether the click position in the EditText area, if the click coordinates in the EditText area directly return False, otherwise return true.
Now that our custom imeobserverlayout is ready, the next step is to add imeobserverlayout to Decorview and its child view linearlayout, to make it easier to use this control, We need to implement the added logic.
Adding logic has to do with the activity to get the root view Decorview, so to pass the current activity in, 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 = (viewgroup) root;
  if (Decorview.getchildcount () > 0) {final View child = Decorview.getchildat (0);
  Decorview.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);
  Decorview.addview (observerlayout, LP);

 }} private static class Imeobserverlayout extends Framelayout {private list<edittext> medittexts;
 Public Imeobserverlayout {Super (context); } public imeobserverlayout (context, AttributeSet attrs) {Super (context, ATTRS); Imeobserverlayout (context, AttributeSet attrs, int defstyleattr) {Super (context, Attrs, defstyleattr
 ); @SuppressLint ("Newapi") public imeobserverlayout (context, AttributeSet attrs, int defstyleattr, int defstyler
 ES) {Super (context, Attrs, defstyleattr, defstyleres);
  } @Override protected void Onattachedtowindow () {Super.onattachedtowindow ();
 Collectedittext (this);
  } @Override protected void Ondetachedfromwindow () {clearedittext ();
 Super.ondetachedfromwindow (); @Override public 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) {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 = 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 FAL
  Se
  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 FAlse;
 } return true;

 }
 }
}

We put the imeobserverlayout in the internal static class way into the Imeobserver, and set the imeobserverlayout for private, the purpose is not to let the outside to do the operation, The imeobserver is then added a static method observer (activity activity) in which Imeobserverlayout is added to the root view Decorview and its child view LinearLayout.
Now everything is ready, test to see the effect, modify the Mainactivity code as follows:

public class Mainactivity extends activity {

 @Override
 protected void onCreate (Bundle savedinstancestate) {
 super.oncreate (savedinstancestate);
 Setcontentview (r.layout.activity_ime);
 Imeobserver.observer (this);
 }


Mainactivity code does not need to be changed, just adding the imeobserver.observer (this) line of code after the Setcontentview () method achieves the function of turning off the input box, is it lightweight and easy to integrate? (*^__^*) ...
We run the program, the effect is as follows:

Well, see the effect feels good, the control itself is not what the technical content, that is, the level of activity is required to be familiar with the hierarchy, and then clear event transfer mechanism, finally can be judged by the coordinates of the click position to decide whether to close the soft keyboard.
OK, custom viewgroup, build your own generic close soft keyboard control here it's over, thanks for watching ...

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.