Last active
February 17, 2018 05:19
-
-
Save mpost/b94275f4321ae0a50973e7cca9d5466c to your computer and use it in GitHub Desktop.
Integrate the Facebook Yoga layout (https://facebook.github.io/yoga/) into the Android layout system as a YogaLayout ViewGroup. The YogaLayout exposes the underlying yoga specific child layout properties on its LayoutParams object as a YogaNode object.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.Nullable; | |
import android.util.AttributeSet; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import com.facebook.yoga.YogaMeasureFunction; | |
import com.facebook.yoga.YogaMeasureMode; | |
import com.facebook.yoga.YogaMeasureOutput; | |
import com.facebook.yoga.YogaNode; | |
import com.facebook.yoga.YogaNodeAPI; | |
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; | |
@SuppressWarnings( "WrongConstant" ) | |
public class YogaLayout extends ViewGroup { | |
private static final int LAST_POSITION = -1; | |
private final MeasureFunction measureFunction; | |
private final YogaNode node; | |
public static class LayoutParams extends ViewGroup.LayoutParams { | |
public final YogaNode node; | |
public LayoutParams( int width, int height ) { | |
super( width, height ); | |
node = new YogaNode(); | |
} | |
public LayoutParams( ViewGroup.LayoutParams params ) { | |
super( params ); | |
node = new YogaNode(); | |
} | |
} | |
public YogaLayout( @NonNull Context context, @Nullable AttributeSet attrs ) { | |
super( context, attrs ); | |
setLayoutParams( generateDefaultLayoutParams() ); | |
node = new YogaNode(); | |
measureFunction = new MeasureFunction(); | |
} | |
public YogaNode getNode() { | |
return node; | |
} | |
@Override | |
protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec ) { | |
node.setWidth( MeasureSpec.getSize( widthMeasureSpec ) ); | |
node.setHeight( MeasureSpec.getSize( heightMeasureSpec ) ); | |
node.calculateLayout(); | |
int layoutWidth = Math.round( node.getLayoutWidth() ); | |
int layoutHeight = Math.round( node.getLayoutHeight() ); | |
setMeasuredDimension( layoutWidth, layoutHeight ); | |
} | |
@Override | |
protected void onLayout( boolean changed, int left, int top, int right, int bottom ) { | |
for( int i = 0; i < getChildCount(); i++ ) { | |
View child = getChildAt( i ); | |
YogaNode childNode = getChildNode( child ); | |
int childLeft = Math.round( childNode.getLayoutX() ); | |
int childTop = Math.round( childNode.getLayoutY() ); | |
int childRight = Math.round( childLeft + childNode.getLayoutWidth() ); | |
int childBottom = Math.round( childTop + childNode.getLayoutHeight() ); | |
child.layout( childLeft, childTop, childRight, childBottom ); | |
} | |
} | |
@Override | |
public void addView( View child, int index, ViewGroup.LayoutParams params ) { | |
super.addView( child, index, params ); | |
YogaNode childNode = getChildNode( child ); | |
childNode.setData( child ); | |
node.addChildAt( childNode, index == LAST_POSITION ? node.getChildCount() : index ); | |
} | |
private YogaNode getChildNode( View child ) { | |
YogaNode childNode; | |
if( child instanceof YogaLayout ) { | |
childNode = ( ( YogaLayout )child ).getNode(); | |
} else { | |
childNode = ( ( LayoutParams )child.getLayoutParams() ).node; | |
childNode.setMeasureFunction( measureFunction ); | |
} | |
return childNode; | |
} | |
@Override | |
public void removeViewAt( int index ) { | |
node.getChildAt( index ).setData( null ); | |
node.removeChildAt( index ); | |
super.removeViewAt( index ); | |
} | |
@Override | |
protected YogaLayout.LayoutParams generateDefaultLayoutParams() { | |
return new YogaLayout.LayoutParams( WRAP_CONTENT, WRAP_CONTENT ); | |
} | |
@Override | |
protected ViewGroup.LayoutParams generateLayoutParams( ViewGroup.LayoutParams params ) { | |
return new YogaLayout.LayoutParams( params ); | |
} | |
private static class MeasureFunction implements YogaMeasureFunction { | |
@Override | |
public long measure( YogaNodeAPI node, | |
float width, YogaMeasureMode widthMode, | |
float height, YogaMeasureMode heightMode ) { | |
Object data = node.getData(); | |
if( data instanceof View ) { | |
View view = ( View )data; | |
view.measure( | |
MeasureSpec.makeMeasureSpec( Math.round( width ), widthMode.intValue() ), | |
MeasureSpec.makeMeasureSpec( Math.round( height ), heightMode.intValue() ) ); | |
int measuredWidth = view.getMeasuredWidth(); | |
int measuredHeight = view.getMeasuredHeight(); | |
return YogaMeasureOutput.make( measuredWidth, measuredHeight ); | |
} | |
return 0; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment