Comment créer une vue ou un bouton cliquable de forme personnalisée dans Android?
Lorsque je clique, je veux éviter de toucher une zone vide.
veuillez aider. Merci.
Question interessante. J'ai essayé quelques solutions et c'est ce que j'ai trouvé qui a le même résultat que ce que vous essayez de réaliser. La solution ci-dessous résout 2 problèmes:
Voici donc la solution en 3 étapes:
Créez deux formes.
Première forme de rectangle simple pour le bouton: 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>
La deuxième forme est utilisée comme masque pour le côté supérieur droit du bouton: shape_button_beer_mask.xml. C'est un simple cercle avec une couleur unie noire.
<?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>
Dans votre mise en page principale, ajoutez le bouton par approche suivante:
Android:soundEffectsEnabled="false"
- de sorte que l'utilisateur ne sentira pas qu'il a appuyé sur quelque chose.Le 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 -->
Dans votre activité principale, vous définissez les événements de clic pour le bouton et le masque comme suit:
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
}
});
C'est ça. Je sais que ce n'est pas une solution parfaite, mais dans votre cas d'utilisation décrit, cela pourrait aider. Je l'ai testé sur mon mobile et voici à quoi il ressemble lorsque vous cliquez sur la zone bleue et rien ne se passera sur les autres zones:
J'espère que cela a aidé d'une manière ou d'une autre :)
Utilisez OnTouch au lieu d'OnClick et vérifiez la valeur alpha de l'image que vous avez utilisée dans le bouton.Si ce n'est pas égal à zéro, faites ce que vous voulez. Vérifiez le code suivant,
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;
}
utiliser la liste des calques, vous pouvez concevoir n'importe quelle forme n'importe quel haut de bouton de dégradé ici est un exemple
<?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>
utilisez des valeurs de rayon -ve pour faire la forme du bouton comme mentionné
vous pouvez essayer celui-ci:
<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"/>
et créez un fichier round.xml dans un dossier dessinable:
<?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>
J'ai eu un problème similaire mais je ne voulais pas dépendre du code derrière pour examiner la valeur en pixels. Je voulais un moyen simple (pas de surcharge de classe) pour contraindre un événement tactile à seulement une sous-partie d'un dessinable. Ci-dessous j'utilise un LinearLayout pour le dessinable puis à l'intérieur je mets un bouton transparent (avec du texte). Je peux ajuster la marge du bouton pour positionner la zone cliquable.
<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>
Plutôt que de faire toutes ces modifications, vous devez utiliser la disposition du cadre dans la partie qui entoure le bouton, et masquer la partie supérieure droite avec quelque chose (circulaire, comme un bouton arrondi) et n'assigner aucun écouteur de clic à cette partie. Cela masque en fait le cadre inférieur (c'est-à-dire votre bouton d'origine) et le masque avec la partie non active.
Meilleure et plus simple solution (as4me) J'ai trouvé ici - c'est un bouton sous-classé et donc il prend en charge le sélecteur. Donc, tout ce que vous devez faire est de dessiner/ajouter des pngs correspondants pour chaque état de bouton pour utiliser le sélecteur et déclarer onClick en xml ou ajouter OnClickListener dans le code et vous êtes prêt à partir.
J'ai essayé la réponse de @Basim Sherif ( link ) et cela fonctionne très bien cependant seulement si la taille du bouton est la même que l'image d'origine. Si le bouton a été étiré, la zone cliquable sera plus petite et si le bouton a été défini sur une taille plus petite, la région cliquable sera plus grande que le bouton réel.
La solution est simple qui consiste à mettre à l'échelle les valeurs iX et iY pour qu'elles correspondent au bitmap d'origine.
Et voici ma version modifiée du 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();
// 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;
}