NewFiveFour | Blog | Portfolio


Android: Custom View's onLayout and onMeasure methods

If you want to layout a custom view’s children yourself, as opposed to making the custom view extend LinearLayout or similar, you need to implement the onLayout and onMeasure methods of the ViewGroup class.

onLayout()

Let’s first look at onLayout(). This tells your custom view’s children where they should lay themselves out:

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
  childCount = getChildCount();
  for(int i=0; i<childCound;i++) {
    View v = getChildAt(i);
    ...
  }
}

This method is called by the ViewGroup, passing in the parent’s dimensions.

The ‘left’ and ‘top’ is the left and right from the custom view’s parent, this is normally zero unless you have set margins on your custom view.

Then we get the number of children and are about to process each in the loop.

The method we must call on each of the views’ in the loop is

v.layout(left, top, right, bottom). 

If ‘left’ or ‘top’ are 0 this means right at the left and top edge of the parent.

If you have defined some padding on your custom view, you must include these in your layout call, otherwise the padding will be in front of the view.

onMeasure()

Before you can call methods such like getMeasuredWidth() on your ViewGroup’s children, however, you must tell them how to measure themselves in onMeasure:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  ...
}

The two parameters passed in are int values which represent the mode and side of the width and height.

Let’s say you passed in match_parent to the layout_width parameter in your View’s XML, and the width of your view’s parent is 400, then the following would be true:

int mode = MeasureSpec.getMode(widthMeasureSpec) // mode == View.MesaureSpec.EXACTLY
int size = MeasureSpec.getSize(widthMeasureSpec) // size == 400

In this method you must call either its super method or setMeasuredDimension() with the width specifications and height specification either passed into the method or created with MeasureSpec.makeMeasureSpec(size, mode).

You must also call the measure(widthSpec, heightSpec) on the child views too.

  for(int i=0; i<childCound;i++) {
    View v = getChildAt(i);
    v.measure(widthSpec, heightSpec);
  }

If you wanted to give each view the same measurements as its parents (BUT WHY???) you could give it its parent’s measure specs, or create your own via the makeMeasureSpec above, perhaps by using a division of the parent’s getMeasuredWidth(), taking into account any padding using the getPadding*() methods.

android android-custom-view

A loading spinner for XMLHTTPRequest

Take this CSS which will show a loading spinner similar to iPhone’s. It takes up the entire background, and has 0.5 transparency.

#cover {
  background: url("http://www.aveva.com/Images/ajax-loader.gif") no-repeat scroll center center rgba(255, 255, 255, 0.5);
  position: absolute;
  height: 100%;
  width: 100%;
}

Now place the html below your holding div <div v-show="loading" id="cover"></div>.

The v-show is vuejs saying only show it when the loading variable is true. But you can turn it on and off however you please.

Let’s turn it on and off – via this.loading=true/false – in our XMLHTTPREQUEST.

I have a very simple reactive observe, onNext and onError. But simply we turn it just before we send the request and turn it off when we receive something back.

observe: function(receiver) {
  var xhttp = new XMLHttpRequest()
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) receiver.onNext(xhttp.response)
    else if(this.readyState ==4 && this.status!=200) receiver.onError(xhttp.statusText)
  }
  xhttp.open("GET", "https://whatever", true)
  xhttp.send()
  this.loading = true
},
onNext: function(pagination) {
  this.loading = false
  ...
},
onError: function(message) {
  this.loading = false
  ...
}
css javascript vuejs

Android: Detect a fling

If you want to detect a fling on a view, create a GestureDetector that for an argument takes a SimpleOnGestureListener.

final static GestureDetector.SimpleOnGestureListener simpleDetector = new GestureDetector.SimpleOnGestureListener() {
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        super.onFling(e1, e2, velocityX, velocityY);
        Log.d("HI", "on fling");
        return true; // If you've consumed it
    }
};
final static GestureDetector detector = new GestureDetector(simpleDetector);

It’s within these methods you calculate what kind of fling it is.

Within your onTouch event listener return with return detector.onTouchEvent(motionEvent);.

And make sure the view you’re listening on is clickable. And that should be it.

android android-fling

Android: Simple view dragging tutorial

Let’s say you’ve added a touch listener to a view. And in that listener you have a motionEvent.

Use this code to start dragging that view in onTouch.

if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
    ClipData data = ClipData.newPlainText("", "");
    View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(
            view);
    view.startDrag(data, shadowBuilder, view, 0);
    return true;
} else {
    return false;
}

The clipdata is the data passed to the drop area. And the shadowBuilder is what the view looks like when dragged.

There’s no drop area, but you can look that up.

android android-drag-drop

Android and Facebook's Litho: Getting started

Litho allows you to declare your view in code with speed optimisations for lists.

It uses flexbox layout logic, via the Facebook Yoga library, allowing you to use your existing web knowledge. This applies to iOS too since Yoga also exists for iOS.

It supports one-directional data binding, thereby allowing you dive into the flux architecture a little.

Let’s do the basic getting started first. Let’s bung all the depenedencies into your app’s build.gradle.

compile 'com.facebook.litho:litho-core:0.2.0'
compile 'com.facebook.litho:litho-widget:0.2.0'
provided 'com.facebook.litho:litho-annotations:0.2.0'
annotationProcessor 'com.facebook.litho:litho-processor:0.2.0'
compile 'com.facebook.soloader:soloader:0.2.0'
debugCompile 'com.facebook.litho:litho-stetho:0.2.0'
compile 'com.facebook.litho:litho-fresco:0.2.0'

Create an Application class in your app and ensure your manifest points to it. In the onCreate method add this:

SoLoader.init(this, false);

In your Activity’s onCreate change the view layout code to:

 ComponentContext c = new ComponentContext(this);
 setContentView(LithoView.create(c, MyComponent.create(c).build()));

We’re creating a Litho context, and then creating a Litho view with that context, and a component too. Where does that MyComponent come from?

@LayoutSpec
public class MyComponentSpec {
    @OnCreateLayout
    static ComponentLayout onCreateLayout(ComponentContext c) {
        return Column.create(c)
                .paddingDip(YogaEdge.ALL, 16)
                .child(Text.create(c)
                        .text("sup")
                        .textSizeSp(40))
                .child(Text.create(c)
                        .text("sup2")
                        .textSizeSp(20))
                .build();

    }
}

The annoation @LayoutSpec takes the class name minus Spec, thereby creating the MyComponent class via facebook’s annoation processor.

We create a Column using flexbox terminology, with two Text children, which are not TextViews incidentally.

Later tutorials will focus on using Android Views within Litho and events I should think.

android litho

Page 2 of 78
Previous Next