From 32b080261845c7508581f9c452d48ffd2401c450 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Fri, 2 Aug 2019 12:50:57 +0200 Subject: Add skeleton build variant --- .../blinkt/openvpn/views/MultiLineRadioGroup.java | 164 +++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 main/src/ui/java/de/blinkt/openvpn/views/MultiLineRadioGroup.java (limited to 'main/src/ui/java/de/blinkt/openvpn/views/MultiLineRadioGroup.java') diff --git a/main/src/ui/java/de/blinkt/openvpn/views/MultiLineRadioGroup.java b/main/src/ui/java/de/blinkt/openvpn/views/MultiLineRadioGroup.java new file mode 100644 index 00000000..8296a644 --- /dev/null +++ b/main/src/ui/java/de/blinkt/openvpn/views/MultiLineRadioGroup.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2012-2018 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + +package de.blinkt.openvpn.views; + +import android.content.Context; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.view.View; +import android.widget.RadioGroup; + +import java.util.HashMap; +import java.util.Map; + +public class MultiLineRadioGroup extends RadioGroup { + private Map viewRectMap; + + public MultiLineRadioGroup(Context context) { + this(context, null); + } + + public MultiLineRadioGroup(Context context, AttributeSet attrs) { + super(context, attrs); + + viewRectMap = new HashMap(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ + int widthMeasurement = MeasureSpec.getSize(widthMeasureSpec); + int heightMeasurement = MeasureSpec.getSize(heightMeasureSpec); + switch (getOrientation()){ + case HORIZONTAL: + heightMeasurement = findHorizontalHeight(widthMeasureSpec, heightMeasureSpec); + break; + case VERTICAL: + widthMeasurement = findVerticalWidth(widthMeasureSpec, heightMeasureSpec); + break; + } + setMeasuredDimension(widthMeasurement, heightMeasurement); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + int count = getChildCount(); + for(int x=0; x < count; ++x) { + View button = getChildAt(x); + Rect dims = viewRectMap.get(button); + button.layout(dims.left, dims.top, dims.right, dims.bottom); + } + } + + private int findHorizontalHeight(int widthMeasureSpec, int heightMeasureSpec){ + int parentHeight = MeasureSpec.getSize(heightMeasureSpec); + int maxRight = MeasureSpec.getSize(widthMeasureSpec) - getPaddingRight(); + + // create MeasureSpecs to accommodate max space that RadioButtons can occupy + int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(maxRight - getPaddingLeft(), + MeasureSpec.getMode(widthMeasureSpec)); + int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec( + parentHeight - (getPaddingTop() + getPaddingBottom()), + MeasureSpec.getMode(heightMeasureSpec)); + + int nextLeft = getPaddingLeft(); + int nextTop = getPaddingTop(); + int maxRowHeight = 0; + viewRectMap.clear(); + // measure and find placement for each RadioButton (results to be used in onLayout() stage) + int count = getChildCount(); + for(int x=0; x < count; ++x){ + View button = getChildAt(x); + measureChild(button, newWidthMeasureSpec, newHeightMeasureSpec); + + maxRowHeight = Math.max(maxRowHeight, button.getMeasuredHeight()); + + // determine RadioButton placement + int nextRight = nextLeft + button.getMeasuredWidth(); + if(nextRight > maxRight){ // if current button will exceed border on this row ... + // ... move to next row + nextLeft = getPaddingLeft(); + nextTop += maxRowHeight; + + // adjust for next row values + nextRight = nextLeft + button.getMeasuredWidth(); + maxRowHeight = button.getMeasuredHeight(); + } + + int nextBottom = nextTop + button.getMeasuredHeight(); + viewRectMap.put(button, new Rect(nextLeft, nextTop, nextRight, nextBottom)); + + // update nextLeft + nextLeft = nextRight; + } + + // height of RadioGroup is a natural by-product of placing all the children + int idealHeight = nextTop + maxRowHeight + getPaddingBottom(); + switch(MeasureSpec.getMode(heightMeasureSpec)){ + case MeasureSpec.UNSPECIFIED: + return idealHeight; + case MeasureSpec.AT_MOST: + return Math.min(idealHeight, parentHeight); + case MeasureSpec.EXACTLY: + default: + return parentHeight; + } + } + + private int findVerticalWidth(int widthMeasureSpec, int heightMeasureSpec){ + int parentWidth = MeasureSpec.getSize(widthMeasureSpec); + int maxBottom = MeasureSpec.getSize(heightMeasureSpec) - getPaddingBottom(); + + // create MeasureSpecs to accommodate max space that RadioButtons can occupy + int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec( + parentWidth - (getPaddingLeft() + getPaddingRight()), + MeasureSpec.getMode(widthMeasureSpec)); + int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(maxBottom - getPaddingTop(), + MeasureSpec.getMode(heightMeasureSpec)); + + int nextTop = getPaddingTop(); + int nextLeft = getPaddingLeft(); + int maxColWidth = 0; + viewRectMap.clear(); + // measure and find placement for each RadioButton (results to be used in onLayout() stage) + int count = getChildCount(); + for(int x=0; x < count; ++x){ + View button = getChildAt(x); + measureChild(button, newWidthMeasureSpec, newHeightMeasureSpec); + + maxColWidth = Math.max(maxColWidth, button.getMeasuredWidth()); + + // determine RadioButton placement + int nextBottom = nextTop + button.getMeasuredHeight(); + if(nextBottom > maxBottom){ // if current button will exceed border for this column ... + // ... move to next column + nextTop = getPaddingTop(); + nextLeft += maxColWidth; + + // adjust for next row values + nextBottom = nextTop + button.getMeasuredHeight(); + maxColWidth = button.getMeasuredWidth(); + } + + int nextRight = nextLeft + button.getMeasuredWidth(); + viewRectMap.put(button, new Rect(nextLeft, nextTop, nextRight, nextBottom)); + + // update nextTop + nextTop = nextBottom; + } + + // width of RadioGroup is a natural by-product of placing all the children + int idealWidth = nextLeft + maxColWidth + getPaddingRight(); + switch(MeasureSpec.getMode(widthMeasureSpec)){ + case MeasureSpec.UNSPECIFIED: + return idealWidth; + case MeasureSpec.AT_MOST: + return Math.min(idealWidth, parentWidth); + case MeasureSpec.EXACTLY: + default: + return parentWidth; + } + } +} \ No newline at end of file -- cgit v1.2.3