Android Custom Shape Button

Jak zrobić niestandardowy kształt klikalny widok lub przycisk w Androidzie?

Kiedy klikam, chcę uniknąć dotykania pustego obszaru .

Tutaj wpisz opis obrazka

Proszę o pomoc. Dziękuję.

Author: Erhan Demirci, 2012-12-13

8 answers

Ciekawe pytanie. Próbowałem kilku rozwiązań i to jest to, co znalazłem, że ma taki sam wynik, co próbujesz osiągnąć. Poniższe rozwiązanie rozwiązuje 2 problemy:

  1. Custom shape as you presented it
  2. prawy górny guzik nie powinien być klikalny

Więc jest to rozwiązanie w 3 krokach:

Krok 1

Utwórz dwa kształty.

  • Pierwszy prosty kształt prostokąta dla przycisku: shape_button_beer.xml

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android" >
    
        <gradient
            android:angle="90"
            android:endColor="#C5D9F4"
            android:startColor="#DCE5FD" />
    
        <corners
            android:bottomLeftRadius="5dp"
            android:bottomRightRadius="5dp"
            android:topLeftRadius="5dp" >
        </corners>
    
    </shape>
    
  • Drugi kształt jest używany jako maska dla prawej górnej części przycisku: shape_button_beer_mask.xml . Jest to proste koło z czarnym jednolitym kolorem.

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="oval" >
    
        <solid android:color="#000000" />
    
    </shape>
    

Krok 2

W głównym układzie Dodaj przycisk przy następnym podejściu:

  • RelativeLayout jest kontenerem tego niestandardowego przycisku
  • pierwsza linia To niebieski przycisk z ikoną piwa i tekstem wewnątrz
  • drugi ImageView to Maska nad niebieskim guzikiem. And here comes dirty trick:
    1. marginesy są ujemne, aby ustawić maskę we właściwym miejscu
    2. definiujemy id, aby móc nadpisać po kliknięciu (patrz krok 3)
    3. android:soundEffectsEnabled="false" - taki, że użytkownik nie będzie czuł, że na coś naciskał.

XML:

    <!-- Custom Button -->
    <RelativeLayout
        android:layout_width="120dp"
        android:layout_height="80dp" >

        <LinearLayout
            android:id="@+id/custom_buttom"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="@drawable/shape_button_beer" >

            <!-- Beer icon and all other stuff -->

            <ImageView
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:layout_marginLeft="5dp"
                android:layout_marginTop="15dp"
                android:src="@drawable/beer_icon" />
        </LinearLayout>

        <ImageView
            android:id="@+id/do_nothing"
            android:layout_width="120dp"
            android:layout_height="100dp"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:layout_marginRight="-50dp"
            android:layout_marginTop="-50dp"
            android:background="@drawable/shape_button_beer_mask"
            android:soundEffectsEnabled="false" >
        </ImageView>
    </RelativeLayout>
    <!-- End Custom Button -->

Krok 3

W głównej aktywności definiujesz zdarzenia dla przycisku i maski w następujący sposób:

LinearLayout customButton = (LinearLayout) findViewById(R.id.custom_buttom);
customButton.setOnClickListener(new View.OnClickListener()
{
    @Override
    public void onClick(View arg0)
    {
        Toast.makeText(getApplicationContext(), "Clicked", Toast.LENGTH_SHORT).show();
    }
});

// Mask on click will do nothing
ImageView doNothing = (ImageView) findViewById(R.id.do_nothing);
doNothing.setOnClickListener(new View.OnClickListener()
{
    @Override
    public void onClick(View arg0)
    {
        // DO NOTHING
    }
});
To wszystko. Wiem, że to nie jest idealne. rozwiązanie, ale w opisanym przypadku użycia może to pomóc. Testowałem go na moim telefonie i tak wygląda po kliknięciu na niebieski obszar i nic się nie stanie na innych obszarach: {]}
  • Tutaj wpisz opis obrazka

Mam nadzieję, że jakoś pomogło:)

 38
Author: sromku,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-14 13:20:52

Użyj OnTouch zamiast OnClick i sprawdź wartość alfa obrazu używanego w przycisku.Jeśli nie równa się zero, rób co chcesz. Sprawdź followsig code,

final Bitmap bitmap;  //Declare bitmap     
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.TheImage);


public boolean onTouch(View v, MotionEvent event) {

        int eventPadTouch = event.getAction();
        float iX=event.getX();
    float iY=event.getY();

        switch (eventPadTouch) {

            case MotionEvent.ACTION_DOWN:
                if (iX>=0 & iY>=0 & iX<bitmap.getWidth() & iY<bitmap.getHeight()) { //Makes sure that X and Y are not less than 0, and no more than the height and width of the image.                
                    if (bitmap.getPixel((int) iX, (int) iY)!=0) {
                        // actual image area is clicked(alpha not equal to 0), do something 
                    }               
                }
                return true;                
        }           
        return false;
}
 14
Author: Basim Sherif,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-25 07:32:14

U można spróbować tego:

        <Button
        android:id="@+id/logout"
        android:layout_width="240dp"
        android:layout_height="28dp"
        android:layout_weight="1"
        android:gravity="center"
        android:text="ContactsDetails"
        android:textColor="#ffffff" android:layout_marginLeft="50dp" android:background="@drawable/round"/>

I utworzyć okrągły.plik xml w katalogu drawable:

        <?xml version="1.0" encoding="utf-8"?>
      <shape xmlns:android="http://schemas.android.com/apk/res/android"
      android:shape="rectangle" android:padding="0dp" android:useLevel = "false">
    <!-- you can use any color you want I used here gray color-->
     <solid android:color="#ABABAB"/> 
       <corners
       android:bottomRightRadius="0dp"
         android:bottomLeftRadius="0dp"
       android:topLeftRadius="0dp"
      android:topRightRadius="70dp"/>
       </shape>
 3
Author: G M Ramesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-14 09:47:53

Użyj layer-list, możesz zaprojektować dowolny kształt dowolnego przycisku gradientu oto przykład

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape xmlns:android="http://schemas.android.com/apk/res/android"
            android:shape="rectangle">
            <corners

                android:topLeftRadius="0dp"
                android:topRightRadius="0dp"
                android:bottomLeftRadius="2dp"
                android:bottomRightRadius="15dp"
                />            
            <!-- The border color -->
            <solid android:color="#ffffff" />
        </shape>
    </item>

    <item android:right="2dp"
        android:left="2dp"
        android:bottom="2dp">
            <shape>            
            <gradient                
                android:startColor="#002a36"
                android:centerColor="#457c8e"
                android:endColor="#e6ffff"               
                android:angle="90" 
                  android:centerY="1"
                android:centerX="0.5"           
                />          

            <corners

                android:topLeftRadius="0dp"
                android:topRightRadius="0dp"
                android:bottomLeftRadius="2dp"
                android:bottomRightRadius="15dp"
                />            
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" 
                />                        
        </shape>
    </item>
</layer-list> 

Użyj wartości promienia-ve, aby nadać kształt przycisku tak, jak wspomniano u

 3
Author: Charan Pai,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-14 09:52:43

Miałem podobny problem, ale nie chciałem polegać na kodzie za zbadać wartość piksela. Chciałem prosty sposób (nie przeciążenie klasy), aby ograniczyć Zdarzenie dotykowe tylko do części podrzędnej drawable. Poniżej używam LinearLayout do rysowania, a następnie w środku umieszczam przezroczysty przycisk (z tekstem). Mogę dostosować margines przycisku, aby ustawić klikalny obszar.

    <LinearLayout
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        android:background="@drawable/circle">
        <Button
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            android:id="@+id/btnTimer1"
            android:text="0:00"
            android:textColor="#ffffff"
            android:textSize="22dp"
            android:layout_margin="20dp"
            android:background="@android:color/transparent"/>
    </LinearLayout>
 1
Author: Mark Owens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-04 14:33:40
 0
Author: Stan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:30

Zamiast tych wszystkich zmian, powinieneś użyć układu ramki w części otaczającej przycisk i zamaskować górną prawą część jakimś czymś (okrągłym, jak zaokrąglony przycisk) i przypisać do tej części bez słuchacza kliknięć. To w efekcie ukrywa dolną ramkę (tj. oryginalny przycisk) i maskuje ją z nieaktywną częścią.

 0
Author: Abhijeet Soni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-24 00:10:55

Próbowałem odpowiedzieć przez @ Basim Sherif (link) i działa świetnie jednak tylko wtedy, gdy rozmiar przycisku jest taki sam jak oryginalnego obrazu. Jeśli przycisk został rozciągnięty, klikalny region będzie mniejszy, a jeśli przycisk został ustawiony na mniejszy rozmiar, klikalny region będzie większy niż rzeczywisty przycisk.

Rozwiązanie jest proste, polega na skalowaniu wartości iX i iY tak, aby pasowały do oryginalnej bitmapy.

A oto moja zmodyfikowana wersja kodu:

final Bitmap bitmap;  //Declare bitmap     
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.TheImage);

public boolean onTouch(View v, MotionEvent event) {

    int eventPadTouch = event.getAction();
    float iX=event.getX();
    float iY=event.getY();

    // Get the dimensions used in the view
    int realW = this.getWidth();
    int realH = this.getHeight();

    // Get the dimensions of the actual image
    int bitmapW = bitmap.getWidth();
    int bitmapH = bitmap.getHeight();

    // Scale the coordinates from the view to match the actual image
    float scaledX = iX * bitmapW / realW;
    float scaledY = iY * bitmapH / realH;

    switch (eventPadTouch) {
        case MotionEvent.ACTION_DOWN:
            if (scaledX >= 0 & scaledY >= 0 & scaledX < bitmap.getWidth() & scaledY < bitmap.getHeight()) { //Makes sure that X and Y are not less than 0, and no more than the height and width of the image.                
                if (bitmap.getPixel((int) scaledX, (int) scaledY)!=0) {
                    // actual image area is clicked(alpha not equal to 0), do something 
                }
            }
            return true;
    }
    return false;
}
 0
Author: Fahad Alduraibi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:32