Recently saw a good library github.com/eleme/UEToo…

1. Ele. me UETool renderings && uses

Since I gave this tool to our design students amway, they love it very much. Those of you who have used the Android developer option know that there is a button to check the boundary, but sometimes, they feel that the function is not enough. Because the developer has the option to display the margins and android Studio’s Layout Inspector or DDMS’s UIAutomator tool

2. A preliminary study on the principle of UETool

Take the capture control feature of UETool’s official Demo as an example.

adb shell dumpsys window w | findstr mCurrent
adb shell dumpsys window w | grep mCurrent

Good goal is me. Ele. Uetool. TransparentActivity

Step 2, look at the target View

It has a member variable called AttrsDialog. It is a custom Dialog that displays the RecyclerView of View properties. We focus on its Adapter

  public static class Adapter extends RecyclerView.Adapter {

        private List<Item> items = new ItemArrayList<>();
        private AttrDialogCallback callback;

        public void setAttrDialogCallback(AttrDialogCallback callback) {
            this.callback = callback;
        }

        public void notifyDataSetChanged(Element element) {
            items.clear();
            for (String attrsProvider : UETool.getInstance().getAttrsProvider()) {
                try {
                    IAttrs attrs = (IAttrs) Class.forName(attrsProvider).newInstance();
                    items.addAll(attrs.getAttrs(element));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            notifyDataSetChanged();
        }
Copy the code

To get to the next breakpoint, let’s skip the complicated wrapping logic and go straight to the running function and the call stack

public class UETCore implements IAttrs {

    @Override
    public List<Item> getAttrs(Element element) {
        List<Item> items = new ArrayList<>();

        View view = element.getView();

        items.add(new SwitchItem("Move", element, SwitchItem.Type.TYPE_MOVE));

        IAttrs iAttrs = AttrsManager.createAttrs(view);
        if(iAttrs ! = null) { items.addAll(iAttrs.getAttrs(element)); } items.add(new TitleItem("COMMON"));
        items.add(new TextItem("Class", view.getClass().getName()));
        items.add(new TextItem("Id", Util.getResId(view)));
        items.add(new TextItem("ResName", Util.getResourceName(view.getResources(), view.getId())));
        items.add(new TextItem("Clickable", Boolean.toString(view.isClickable()).toUpperCase()));
        items.add(new TextItem("Focused", Boolean.toString(view.isFocused()).toUpperCase()));
        items.add(new AddMinusEditItem("Width (dp), element, EditTextItem.Type.TYPE_WIDTH, px2dip(view.getWidth())));
        items.add(new AddMinusEditItem(Height (dp), element, EditTextItem.Type.TYPE_HEIGHT, px2dip(view.getHeight())));
        items.add(new TextItem("Alpha", String.valueOf(view.getAlpha())));
        Object background = Util.getBackground(view);
        if (background instanceof String) {
            items.add(new TextItem("Background", (String) background));
        } else if (background instanceof Bitmap) {
            items.add(new BitmapItem("Background", (Bitmap) background));
        }
        items.add(new AddMinusEditItem(PaddingLeft (dp), element, EditTextItem.Type.TYPE_PADDING_LEFT, px2dip(view.getPaddingLeft())));
        items.add(new AddMinusEditItem(PaddingRight (dp), element, EditTextItem.Type.TYPE_PADDING_RIGHT, px2dip(view.getPaddingRight())));
        items.add(new AddMinusEditItem(PaddingTop (dp), element, EditTextItem.Type.TYPE_PADDING_TOP, px2dip(view.getPaddingTop())));
        items.add(new AddMinusEditItem(PaddingBottom (DP), element, EditTextItem.Type.TYPE_PADDING_BOTTOM, px2dip(view.getPaddingBottom())));

        return items;
    }
Copy the code

There’s a View object and of course dialog is showing all the properties of the View, so it’s weird, this View is MainActivity, how does this new TransparentActivity get the data source don’t panic, look at this function stack, Notice the Element of the EditAttrLayout class triggerActionUp method

@Override
        public void triggerActionUp(MotionEvent event) {
            final Element element = getTargetElement(event.getX(), event.getY());
            if(element ! = null) { EditAttrLayout.this.element = element; invalidate();if (dialog == null) {
                    dialog = new AttrsDialog(getContext());
                    dialog.setAttrDialogCallback(new AttrsDialog.AttrDialogCallback() {
                        @Override
                        public void enableMove() { mode = new MoveMode(); dialog.dismiss(); }}); dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { element.reset(); invalidate(); }}); } dialog.show(element); }}Copy the code

GetTargetElement (event.getx (), event.gety ())); Clicking in will jump to the getTargetElement method of the parent class CollectViewsLayout

 protected Element getTargetElement(float x, float y) {
        Element target = null;
        for (int i = elements.size() - 1; i >= 0; i--) {
            final Element element = elements.get(i);
            if (element.getRect().contains((int) x, (int) y)) {
                if(element ! = childElement) { childElement = element; parentElement = element; }else if(parentElement ! = null) { parentElement = parentElement.getParentElement(); } target = parentElement;break; }}if (target == null) {
            Toast.makeText(getContext(), getResources().getString(R.string.uet_target_element_not_found, x, y), Toast.LENGTH_SHORT).show();
        }
        return target;
    }
Copy the code

Element List< element > Add (command +f) or CTRL + F (command + F) searches for elements. Add to find the function that sets the data source

private void traverse(View view) {
        if (UETool.getInstance().getFilterClasses().contains(view.getClass().getName())) return;
        if(view.getAlpha() == 0 || view.getVisibility() ! = View.VISIBLE)return;
        if (getResources().getString(R.string.uet_disable).equals(view.getTag())) return;
        elements.add(new Element(view));
        if (view instanceof ViewGroup) {
            ViewGroup parent = (ViewGroup) view;
            for(int i = 0; i < parent.getChildCount(); i++) { traverse(parent.getChildAt(i)); }}}Copy the code

Create a breakpoint to look at the call stack, or just under the Element constructor to skip the above analysis from Element to Elemnets and look at the figure below

UETool gets the targetActivity (MainActivity), reflection gets the decoreView, and then calls the Traverse method of the CollectViewsLayout class, the parent of the EditAttrLayout class.

To sum up chronological order, the CollectViewsLayout class onAttachedToWindow gets the decoreView of the target MainActivity by reflection, I wrapped the Element of the decoreView in the CollectViewsLayout member variable List

Elements add, and then the user, me, clicked the Action control button on UETool, UP event AttrsDialog show method when calling adapter. The notifyDataSetChanged (element); Set the Adapter as the data source the List

of the various element attributes unpacked by UETCore

All right, so that’s it. The code of Ele. me god is so roughly finished, the code encapsulation is very good, it is suggested that interested students can have a look and learn.