summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArne Schwabe <arne@rfc2549.org>2018-07-23 13:22:43 +0200
committerArne Schwabe <arne@rfc2549.org>2018-07-23 13:23:40 +0200
commitc74088f1ec3536fecc146d7f441d5250e661fc7b (patch)
tree76c55e5f27ec4f3bf7962ce2aa94dcb3985f9fea
parenta733aad2ec8ed8cdb8b6d9d584c172488eacfa8f (diff)
Implement multiline radio group (closes #888)
-rw-r--r--main/src/main/java/de/blinkt/openvpn/views/MultiLineRadioGroup.java164
-rw-r--r--main/src/main/res/layout/server_card.xml4
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"