diff options
author | Arne Schwabe <arne@rfc2549.org> | 2018-07-23 13:22:43 +0200 |
---|---|---|
committer | Arne Schwabe <arne@rfc2549.org> | 2018-07-23 13:23:40 +0200 |
commit | c74088f1ec3536fecc146d7f441d5250e661fc7b (patch) | |
tree | 76c55e5f27ec4f3bf7962ce2aa94dcb3985f9fea | |
parent | a733aad2ec8ed8cdb8b6d9d584c172488eacfa8f (diff) |
Implement multiline radio group (closes #888)
-rw-r--r-- | main/src/main/java/de/blinkt/openvpn/views/MultiLineRadioGroup.java | 164 | ||||
-rw-r--r-- | main/src/main/res/layout/server_card.xml | 4 |
2 files changed, 166 insertions, 2 deletions
diff --git a/main/src/main/java/de/blinkt/openvpn/views/MultiLineRadioGroup.java b/main/src/main/java/de/blinkt/openvpn/views/MultiLineRadioGroup.java new file mode 100644 index 00000000..8296a644 --- /dev/null +++ b/main/src/main/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<View, Rect> viewRectMap; + + public MultiLineRadioGroup(Context context) { + this(context, null); + } + + public MultiLineRadioGroup(Context context, AttributeSet attrs) { + super(context, attrs); + + viewRectMap = new HashMap<View, Rect>(); + } + + @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 diff --git a/main/src/main/res/layout/server_card.xml b/main/src/main/res/layout/server_card.xml index 5d13cff0..3b214bbb 100644 --- a/main/src/main/res/layout/server_card.xml +++ b/main/src/main/res/layout/server_card.xml @@ -121,7 +121,7 @@ android:layout_height="wrap_content" /> - <RadioGroup + <de.blinkt.openvpn.views.MultiLineRadioGroup android:id="@+id/proxyradiogroup" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -170,7 +170,7 @@ android:text="@string/tor_orbot" /> - </RadioGroup> + </de.blinkt.openvpn.views.MultiLineRadioGroup> <TextView android:id="@+id/proxyport_label" style="@style/item" |