Hexagonal button with hexagonal touch surface

I need to create the same buttons as in the image below. Button should be with text inside.

  • enter image description here

When I was doing the XML layout, I ran into the problem of touching the Button . Each next button closes the previous button with the rectangular Button area.

  • enter image description here

Is it correct to place hexagons in XML markup, as I did, to implement hexagons, for example, in a picture? Please help me solve the problem with the touch area and, if possible, tell me how to create the layout correctly, because I am not sure if I am doing this correctly.

Here is part of my test layout:

  <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_marginTop="?attr/actionBarSize"> <Button android:id="@+id/button1" android:layout_width="130dp" android:layout_height="134dp" android:background="@drawable/hexagon_shape_img" android:text="Home page" android:textSize="@dimen/small_text" /> <Button android:id="@+id/button2" android:layout_width="130dp" android:layout_height="134dp" android:layout_marginLeft="65dp" android:layout_marginTop="-20dp" android:background="@drawable/hexagon_shape_img" android:text="Tavern" android:textSize="@dimen/small_text" /> </LinearLayout> 
+5
source share
1 answer

Well, that turned out to be harder than I thought. The main problem is that the highest Z-ordered button always receives a touch event, but does not send it to the lower Z-orders, even if it does not destroy the event. To get both buttons to see the event, a crawl is needed. Here's the basic approach:

1: Create a container in the Snippet / Activity in which the hex buttons are currently stored

2: Create a fragment containing buttons and another button on top of all of them with alpha = 0

3: Add the getOverlay (): View method, which returns the alpha = 0 button

4: implement hitTest (): Button method in fragment

5: In the main part of Activity / Fragment, configure listeners to handle events of touching the overlay button

I made (and tested) an application to demonstrate the concept. I am going to leave a hitTest to you as it is rather tedious

activity_main.xml:

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <FrameLayout android:id="@+id/main_container" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout> 

fragment_buttons.xml:

 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.me.testapplication.Buttons"> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/lorem"/> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/lorem_ipsum" android:alpha="0.4"/> <Button android:id="@+id/overlay" android:layout_width="match_parent" android:layout_height="match_parent" android:alpha="0"/> </FrameLayout> 

MainActivity.java:

 public class MainActivity extends ActionBarActivity { public static final String DEBUG_TAG = "TEST"; private Buttons mButtons; private GestureDetector mGestureDetector; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButtons = Buttons.newInstance(); getFragmentManager().beginTransaction() .replace(R.id.main_container, mButtons) .commit(); mGestureDetector = new GestureDetector(this, mGestureListener); } @Override protected void onStart() { super.onStart(); View overlay = mButtons.getOverlay(); if (overlay != null) { overlay.setOnTouchListener(mTouchListener); } } ... private View.OnTouchListener mTouchListener = new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return mGestureDetector.onTouchEvent(event); } }; private GestureDetector.OnGestureListener mGestureListener =new GestureDetector.OnGestureListener() { @Override public boolean onDown(MotionEvent e) { String buttonHit = mButtons.hitTest(e); Log.i(DEBUG_TAG, buttonHit); return true; } ... }; } 

Buttons.java:

 public class Buttons extends Fragment { Button mButton1, mButton2; View mOverlay; public static Buttons newInstance() { return new Buttons(); } public Buttons() {} @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.fragment_buttons, container, false); mButton1 = (Button) root.findViewById(R.id.button1); mButton2 = (Button) root.findViewById(R.id.button2); mOverlay = root.findViewById(R.id.overlay); return root; } @Nullable public View getOverlay() { return mOverlay; } public String hitTest(MotionEvent event) { float x = event.getX(); float y = event.getY(); if (x > mButton1.getLeft() && mButton1.getRight() > x && y > mButton1.getTop() && mButton1.getBottom() > y) { return "Button 1"; } else if (x > mButton2.getLeft() && mButton2.getRight() > x && y > mButton2.getTop() && mButton2.getBottom() > y) { return "Button 2"; } else { return "None"; } } } 

Good luck.

ETA: hitTest Sample

 /** * UNTESTED * I'm going to assume square buttons (equilateral hexagons) * this just calculates if the distance from the center of the button is less than its width. It may be good enough for government work. */ public View hitTest(MotionEvent e) { for (Button hex : SomeIterableThingHoldingYourButtons) { //ArrayList<Button> maybe float x = e.getX(); float y = e.getY(); if (isInHex(hex, x, y)) return hex; } return null; } private boolean isInHex(Button hex, float x, float y) { float radius = hex.getRight() - hex.getLeft() / 2; float centerX = hex.getLeft() + radius; float centerY = hex.getTop() + radius; float dist = FloatMath.sqrt(...) //euclidean distance return dist < radius; } 
+2
source

Source: https://habr.com/ru/post/1211765/


All Articles