An example of a label container control in Android _android

Source: Internet
Author: User
Tags int size static class

Objective

In some of the app we can see some container control, and we usually use some of the layout of some different ways, they generally can automatically adapt to the width of the screen layout, according to some understanding of the custom control, today, write a simple label container control, to everyone reference learning.

Here's an example I intercepted on my phone that was intercepted on the MIUI8 system.

This is my implementation of the effect diagram

Principle Introduction

Depending on the effect analysis of the entire control, you can roughly analyze the controls from the following angles:

1. The first involves customizing the ViewGroup, because the existing controls do not meet our layout effect, it involves rewriting onmeasure and onlayout, where the problem is to customize the view, We need to consider the Padding property of the view, and in the custom ViewGroup we need to consider the margin property of the child control in onlayout otherwise the subclass setting this property will fail. The drawing process for the entire view is this:

The topmost viewroot executes performtraversals and then begins to measure, layout, and draw levels of each view, the whole process is one layer at a time, that is to say, the parent view measures the method of the child view, the view method of the child view, has been measured to the leaf node, performtraversals This function translation is very straightforward, the implementation of traversal, it illustrates this hierarchical relationship.

2. The control form and ListView forms are similar , so here I also imitate the ListView adapter mode to implement the control content operation, Here is a simple explanation for the Notifydatasetchanged method of ListView's Setadapter and adapter:

After ListView calls Setadapter, ListView registers a observer object to the adapter, and then when we change the data on the adapter, We call the adapter Notifydatasetchanged method, which notifies all observer objects that are listening for changes to the adapter data, which is the typical listener pattern. At this time because the internal member object in ListView listen to the event, you can know that the data source has changed, we need to redraw the entire control, the following some relevant source code.

Adapter's notifydatasetchanged

public void notifydatasetchanged () {
    mdatasetobservable.notifychanged ();
  }

The Setadapter method of ListView

@Override public
  void Setadapter (ListAdapter adapter) {
    /**
     * Every time you set up a new fit, you can do a listening operation if you have it now
     .
    if (madapter!= null && mdatasetobserver!= null) {
      Madapter.unregisterdatasetobserver ( mdatasetobserver);
    }

    Resetlist ();
    Mrecycler.clear ();
    /** omit part of the code ...  .. */
    if (madapter!= null) {
      mareallitemsselectable = madapter.areallitemsenabled ();
      Molditemcount = Mitemcount;
      Mitemcount = Madapter.getcount ();
      Checkfocus ();

      /**
      * Here the adapter is set up for listening,
      * Using the object of the Adapterdatasetobserver class, which is defined in ListView's parent class Adapterview
      . Mdatasetobserver = new Adapterdatasetobserver ();
      Madapter.registerdatasetobserver (mdatasetobserver);
      /** omit
    /} else {
      /** omitted *

    /} requestlayout ();
  }

Internal class Adapterdatasetobserver in Adapterview

Class Adapterdatasetobserver extends Datasetobserver {

    private parcelable minstancestate = null;

    @Override public void onchanged () {* * * * * * * * * * * * * * * * * *
      checkfocus ();
      Requestlayout ();
    }

    @Override public void oninvalidated () {* * * * * * * * * * * * * * * * * *
      checkfocus ();
      Requestlayout ();
    }

    public void Clearsavedstate () {
      minstancestate = null;
    }
  }

A piece of pseudo code indicates

listview{
  Observer observer{
     onChange () {change
       ;
     }
  }

  Setadapter (Adapter Adapter) {
     adapter.register (Observer);
  }
}

adapter{
  list<observer> mobservable;
  Register (Observer) {
    MOBSERVABLE.ADD (Observer);
  }
  Notifydatasetchanged () {for
    (I-->mobserverable.size ()) {
      mobserverable.get (i). OnChange
    }
  }
}

Implementation process

Get the ViewItem interface

Package humoursz.gridtag.test.adapter;

Import Android.view.View;

Import java.util.List;

/**
 * Created by Zhangzhiquan on 2016/7/19.
 * * Public
interface Gridetagbaseadapter {
  list<view> getviews ();
}

Abstract Adapter Absgridtagsadapter

Package humoursz.gridtag.test.adapter;

Import android.database.DataSetObservable;
Import Android.database.DataSetObserver;

/**
 * Created by Zhangzhiquan on 2016/7/19.
 * * Public
abstract class Absgridtagsadapter implements Gridetagbaseadapter {

  datasetobservable mobservable = New Datasetobservable ();

  public void notification () {
    mobservable.notifychanged ();
  }
  public void Registerobserve (Datasetobserver observer) {
    MOBSERVABLE.REGISTEROBSERVER (Observer);
  }
  public void Unregisterobserve (Datasetobserver observer) {
    MOBSERVABLE.UNREGISTEROBSERVER (Observer);
  }
}

The desired adapter in this effect implements the GetView interface, mainly mimicking the ListView Baseadapter

Package humoursz.gridtag.test.adapter;
Import Android.content.Context;
Import Android.view.LayoutInflater;
Import Android.view.View;


Import Android.widget.TextView;
Import java.util.ArrayList;

Import java.util.List;
Import HUMOURSZ.GRIDTAG.TEST.R;
Import Humoursz.gridtag.test.util.UIUtil;

Import Humoursz.gridtag.test.widget.GridTagView;
 /** * Created by Zhangzhiquan on 2016/7/19.

  * * public class Mygridtagadapter extends Absgridtagsadapter {private context mcontext;

  Private list<string> mtags;
    Public Mygridtagadapter (context context, list<string> tags) {mcontext = context;
  Mtags = tags;
    @Override public list<view> getviews () {list<view> List = new arraylist<> (); for (int i = 0; i < mtags.size (); i++) {TextView TV = (TextView) layoutinflater.from (mcontext). Infla

      TE (r.layout.grid_tag_item_text, null);

      Tv.settext (Mtags.get (i));
        Gridtagview.layoutparams LP = new Gridtagview  .

      Layoutparams (GridTagView.LayoutParams.WRAP_CONTENT, GridTagView.LayoutParams.WRAP_CONTENT);

      Lp.margin (uiutil.dp2px (Mcontext, 5));

      TV.SETLAYOUTPARAMS (LP);
    LIST.ADD (TV);
  } return list; }
}

and finally the lead Gridtagsview control

Package humoursz.gridtag.test.widget;
Import Android.content.Context;
Import Android.database.DataSetObserver;
Import Android.util.AttributeSet;
Import Android.util.Log;
Import Android.view.View;


Import Android.view.ViewGroup;

Import java.util.List;

Import Humoursz.gridtag.test.adapter.AbsGridTagsAdapter;
 /** * Created by Zhangzhiquan on 2016/7/18.

  * * public class Gridtagview extends ViewGroup {private int mlines = 1;

  private int mwidthsize = 0;

  Private Absgridtagsadapter Madapter;

  Private Gtobserver Mobserver = new Gtobserver ();
  Public Gridtagview {This (context, NULL);
  Public Gridtagview (context, AttributeSet attrs) {This (context, attrs, 0);
  Public Gridtagview (context, AttributeSet attrs, int defstyleattr) {Super (context, attrs, defstyleattr); } public void Setadapter (Absgridtagsadapter adapter) {if (Madapter!= null) {Madapter.unregisterobserve (M
    Observer); } Madapter = AdaptEr
    Madapter.registerobserve (Mobserver);
  Madapter.notification (); @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {int widthsize = MEASURESPEC.G
    Etsize (WIDTHMEASURESPEC);
    int heightsize = measurespec.getsize (Heightmeasurespec);
    int curwidthsize = 0;
    int childheight = 0;
    Mlines = 1;
      for (int i = 0; i < Getchildcount (); ++i) {View child = Getchildat (i);
      Measurechild (Child, Widthmeasurespec, Heightmeasurespec);
      Curwidthsize + = getchildrealwidthsize (child); if (Curwidthsize > Widthsize) {/** * Calculates the total number of rows needed to compute the height of the control * The calculation method is if the current control is down and the width exceeds the * container
        The height of itself, put on the next line * * * curwidthsize = getchildrealwidthsize (child);
      mlines++; } if (childheight = = 0) {/** * Gets the height of the word view as the basis for calculation on the first calculation * * * childheight = Getchildrea
      Lheightsize (child);
    } mwidthsize = Widthsize; Setmeasureddimension (WidthsizE, childheight = 0?

  Heightsize:childheight * mlines);
      @Override protected void OnLayout (Boolean changed, int l, int t, int r, int b) {if (getchildcount () = 0)
    Return
    int childcount = Getchildcount ();
    Layoutparams LP = Getchildlayoutparams (Getchildat (0)); 
    /** * The initial left boundary is the same as the initial upper boundary principle after the margin of its own padding and the child (* * * * the same as/int left = Getpaddingleft () + Lp.leftmargin;
    int top = Getpaddingtop () + Lp.topmargin;
    int curleft = left;

      for (int i = 0; i < ChildCount. ++i) {View child = Getchildat (i);
      int right = Curleft + getchildrealwidthsize (child); /** * Calculation If you drop the entire line to the right after the current attempt * if you exceed the width of the control, put it on the next line, and the margin is restored, the top margin equals the start of the next line. * IF (right > Mwidthsize)
        {top = getchildrealheightsize (child);
      Curleft = left;
      } child.layout (Curleft, top, Curleft + child.getmeasuredwidth (), Top + child.getmeasuredheight ()); /** * The left start distance of the next control is to the right of the previous control/CurlefT + = getchildrealwidthsize (child); /** * Get childview actual width * @param child * @return The actual width of the control, need to count margin otherwise margin not effective * * Private int get
    Childrealwidthsize (View child) {layoutparams LP = Getchildlayoutparams (child);
    int size = Child.getmeasuredwidth () + Lp.leftmargin + lp.rightmargin;
  return size; /** * Get childview actual occupation Height * @param child * @return Actual occupation height needs to consider up and down margin * * Private int Getchildrealheightsi
    Ze (View child) {layoutparams LP = Getchildlayoutparams (child);
    int size = Child.getmeasuredheight () + Lp.topmargin + lp.bottommargin;
  return size; /** * Get layoutparams Property * @param child * @return/private Layoutparams getchildlayoutparams (View child
    ) {Layoutparams LP;
    if (Child.getlayoutparams () instanceof layoutparams) {LP = (Layoutparams) child.getlayoutparams ();
    else {LP = (Layoutparams) generatelayoutparams (Child.getlayoutparams ());
  } return LP; } @OverRide public viewgroup.layoutparams generatelayoutparams (AttributeSet attr) {return new Layoutparams (GetContext (), a
  TTR); } @Override protected Viewgroup.layoutparams generatelayoutparams (Viewgroup.layoutparams p) {return new LAYOUTPA
  Rams (P);  public static class Layoutparams extends Marginlayoutparams {public layoutparams (context C, AttributeSet Attrs)
    {Super (C, attrs);
    public layoutparams (int width, int height) {Super (width, height);
    Public Layoutparams (Marginlayoutparams source) {super (source);
    Public Layoutparams (Viewgroup.layoutparams source) {super (source);
    public void marginleft (int left) {this.leftmargin = left;
    public void marginright (int r) {this.rightmargin = R;
    The public void margintop (int t) {this.topmargin = t;
    public void marginbottom (int b) {this.bottommargin = b; } public void margin (int m) {THIS.LEftmargin = m;
      This.rightmargin = m;
      This.topmargin = m;
    This.bottommargin = m; } private class Gtobserver extends Datasetobserver {@Override public void onchanged () {Removeallvi
      EWS ();
      list<view> list = Madapter.getviews ();
      for (int i = 0; i < list.size (); i++) {AddView (List.get (i));
    @Override public void oninvalidated () {log.d ("Mrz", "FD"); }
  }
}

mainactivity

 package humoursz.gridtag.test;
Import android.support.v7.app.AppCompatActivity;
Import Android.os.Bundle;

Import Android.view.View;

Import java.util.List;
Import Humoursz.gridtag.test.adapter.MyGridTagAdapter;
Import Humoursz.gridtag.test.util.ListUtil;

Import Humoursz.gridtag.test.widget.GridTagView;
  public class Mainactivity extends Appcompatactivity {mygridtagadapter adapter;
  Gridtagview Mgridtag;
  List<string> mlist;
    @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
    Setcontentview (R.layout.activity_main);
    Mgridtag = (Gridtagview) Findviewbyid (r.id.grid_tags);
    Mlist = Listutil.getgridtagslist (20);
    adapter = new Mygridtagadapter (this,mlist);
  Mgridtag.setadapter (adapter);
    public void OnClick (View v) {mlist.removeall (mlist);
    Mlist.addall (Listutil.getgridtagslist (20));
  Adapter.notification (); }
}

XML file

<?xml version= "1.0" encoding= "Utf-8"?> <relativelayout 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"
  tools:context= "humoursz.gridtag.test.MainActivity" >

  < Humoursz.gridtag.test.widget.GridTagView
    android:id= "@+id/grid_tags"
    android:layout_width= "Match_ Parent "
    android:layout_height=" wrap_content >
   
 

The above is the entire implementation of the label container control in Android, so a simple control is written, with the main need to be aware of measure and layout Otherwise many effects will fail. Controls such as the Andong LinearLayout are actually a lot more complicated to implement, because the supported properties are really too much, and hands-on practice helps to understand and hopefully this article will help everyone in Android development.

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.