package org.commcare.views;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import org.commcare.dalvik.R;
/**
* A shrinking linear layout is capable of denoting one child view which can change its size
* if the full space is not needed.
*
* Normally a linear layout requires either fully laying out (IE: Pre-determined static sizes or
* ratios) all of its children _or_ accepting that if the linear layout grows larger than its parent
* some views will be cut off.
*
* When designing a shrinking layout, the view can be laid out fully "expanded" (IE: All of the
* child views are the largest they will ever be), then one view can be chosen to shrink to its
* "natural" width if it doesn't need the full space. This allows for things like text fields with
* an element next to the text that can grow horizontally _until_ running into the fully "expanded"
* layout.
*
* Limitations:
* This layout is incrementally slower than a traditional linear layout.
* The view will currently only shrink horizontally
*
* Created by ctsims on 5/18/2016.
*/
public class ShrinkingLinearLayout extends LinearLayout {
private int shrinkingViewId = -1;
public ShrinkingLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
loadViewConfig(context, attrs);
}
private void loadViewConfig(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ShrinkingLinearLayout);
shrinkingViewId = typedArray.getResourceId(R.styleable.ShrinkingLinearLayout_shrinkable_view, -1);
typedArray.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
View dynamicView = this.findViewById(shrinkingViewId);
if(shrinkingViewId == -1 || dynamicView == null) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
//Figure out how much width the constrained view _really_ wants
dynamicView.measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec);
int desiredWidth = dynamicView.getMeasuredWidth();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//If after everything is measured the view is bigger than it needs to be, forget the other
//layout directives, and have the view only request that width
if (dynamicView.getMeasuredWidth() > desiredWidth) {
LayoutParams params = (LinearLayout.LayoutParams)dynamicView.getLayoutParams();
//NOTE: Any parameters used to control the final size will need to be copied in this
//way. API19+ supports copy construction for layout params, but that's a ways away
int oldWidth = params.width;
float oldWeight = params.weight;
params.width = desiredWidth;
params.weight = 0;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//reset the parameters, since they are directives, not values.
params.width = oldWidth;
params.weight = oldWeight;
}
}
}