Skip to content

Instantly share code, notes, and snippets.

@moagrius
Last active July 1, 2016 17:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save moagrius/c614700fec7fc308c6f922c5b0244e78 to your computer and use it in GitHub Desktop.
Save moagrius/c614700fec7fc308c6f922c5b0244e78 to your computer and use it in GitHub Desktop.
This is a re-usable widget that accepts one child. That child will always show as much of that child as possible, without clipping, and extending to the appropriate edge, then centered in the remaining space.
package com.michaeldunn.experiments.widgets;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.michaeldunn.experiments.R;
/**
* Created by michaeldunn on 7/1/16.
*/
public class CenterContainViewGroup extends ViewGroup {
private static final String TAG = CenterContainViewGroup.class.getSimpleName();
private enum Orientation {
UNDEFINED,
PORTRAIT,
LANDSCAPE
}
private int mIntrinsicWidth;
private int mIntrinsicHeight;
private int mAvailableWidth;
private int mAvailableHeight;
private Orientation mIntrinsicOrientation = Orientation.UNDEFINED;
public CenterContainViewGroup(Context context) {
this(context, null);
}
public CenterContainViewGroup(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CenterContainViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if(attrs != null) {
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CenterContainViewGroup, 0, 0);
try {
int intrinsicWidth = typedArray.getInt(R.styleable.CenterContainViewGroup_natural_width, 0);
int intrinsicHeight = typedArray.getInt(R.styleable.CenterContainViewGroup_natural_height, 0);
setIntrinsicWidth(intrinsicWidth);
setIntrinsicHeight(intrinsicHeight);
} finally {
typedArray.recycle();
}
}
}
public int getIntrinsicHeight() {
return mIntrinsicHeight;
}
public void setIntrinsicHeight(int intrinsicHeight) {
mIntrinsicHeight = intrinsicHeight;
determineIntrinsicOrientation();
}
public int getIntrinsicWidth() {
return mIntrinsicWidth;
}
public void setIntrinsicWidth(int intrinsicWidth) {
mIntrinsicWidth = intrinsicWidth;
determineIntrinsicOrientation();
}
private void determineIntrinsicOrientation(){
mIntrinsicOrientation = mIntrinsicHeight > mIntrinsicWidth ? Orientation.PORTRAIT : Orientation.LANDSCAPE;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mAvailableWidth = MeasureSpec.getSize(widthMeasureSpec);
mAvailableHeight = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(mAvailableWidth, mAvailableHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
View child = getChildAt(0);
if (mIntrinsicOrientation != Orientation.UNDEFINED && child.getVisibility() != GONE) {
int drawingWidth = 0;
int drawingHeight = 0;
int offsetX;
int offsetY;
int effectiveWidth = mIntrinsicWidth;
int effectiveHeight = mIntrinsicHeight;
if(effectiveWidth > mAvailableWidth){
effectiveHeight *= (effectiveWidth / (float) mAvailableWidth);
effectiveWidth = mAvailableWidth;
}
if(effectiveHeight > mAvailableHeight){
effectiveWidth *= (effectiveHeight / (float) mAvailableHeight);
effectiveHeight = mAvailableHeight;
}
switch(mIntrinsicOrientation){
case LANDSCAPE:
float heightFactor = mAvailableWidth / (float) effectiveWidth;
drawingHeight = (int) (effectiveHeight * heightFactor);
drawingWidth = mAvailableWidth;
if(drawingHeight > mAvailableHeight){
drawingWidth *= (mAvailableHeight / (float) drawingHeight);
drawingHeight = mAvailableHeight;
}
break;
case PORTRAIT:
float widthFactor = mAvailableHeight / (float) effectiveHeight;
drawingWidth = (int) (effectiveWidth * widthFactor);
drawingHeight = mAvailableHeight;
if(drawingWidth > mAvailableWidth){
drawingHeight *= (mAvailableWidth / (float) drawingWidth);
drawingWidth = mAvailableWidth;
}
break;
}
offsetY = (mAvailableHeight - drawingHeight) / 2;
offsetX = (mAvailableWidth - drawingWidth) / 2;
Log.d(TAG, "x=" + offsetX + ", y=" + offsetY + ", w=" + drawingWidth + ", h=" + drawingHeight);
child.layout(offsetX, offsetY, drawingWidth + offsetX, drawingHeight + offsetY);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment