Android: comment dessiner une bordure sur un LinearLayout

197

J'ai trois fichiers. Le XML, la fonction de dessin et l'activité principale. J'en ai LinearLayoutdans mon fichier XML.

<LinearLayout android:orientation="horizontal"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:layout_weight="1">
    <LinearLayout android:layout_width="fill_parent"
                  android:layout_height="fill_parent"
                  android:layout_weight="1"
                  android:background="#ef3"
                  android:id="@+id/img01"/>
    <LinearLayout android:layout_width="fill_parent"
                  android:layout_height="fill_parent"
                  android:layout_weight="1"
                  android:background="#E8A2B4"
                  android:id="@+id/img02"/>
</LinearLayout>

Voici la fonction de dessin:

public class getBorder extends TextView {
    public getBorder(Context context) {
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();

        paint.setColor(android.graphics.Color.RED);

        canvas.drawLine(0, 0, this.getWidth() - 1, 0, paint);
        canvas.drawLine(0, 0, 0, this.getHeight() - 1, paint);
        canvas.drawLine(this.getWidth() - 1, 0, this.getWidth() - 1,
            this.getHeight() - 1, paint);
        canvas.drawLine(0, this.getHeight() - 1, this.getWidth() - 1,
            this.getHeight() - 1, paint);
    }
}

Et c'est l'activité principale:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    final getBorder getBorder = new getBorder(this);
    final LinearLayout img01 = (LinearLayout) findViewById(R.id.img01);
    img01.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            getBorder.setWidth(100);
            getBorder.setHeight(100);
            img01.addView(getBorder);
        }
    });       
}

Le programme pouvait dessiner une bordure mais la taille ne correspondait pas au LinearLayout. Et quand je clique à LinearLayoutnouveau sur, le programme plante.

Une autre chose, je veux dessiner deux cercles au centre de la LinearLayout, mais comment pourrais-je déterminer les coordonnées du centre?

SPG
la source

Réponses:

460

Avez-vous vraiment besoin de le faire par programmation?

En considérant le titre: vous pouvez utiliser un ShapeDrawable en tant qu'androïde: arrière-plan…

Par exemple, définissons res/drawable/my_custom_background.xmlcomme:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
  <corners
      android:radius="2dp"
      android:topRightRadius="0dp"
      android:bottomRightRadius="0dp"
      android:bottomLeftRadius="0dp" />
  <stroke
      android:width="1dp"
      android:color="@android:color/white" />
</shape>

et définissez android: background = "@ drawable / my_custom_background".

Je n'ai pas testé mais ça devrait marcher.

Mettre à jour:

Je pense que c'est mieux de tirer parti de la puissance des ressources drawable de forme xml si cela correspond à vos besoins. Avec un projet "from scratch" (pour android-8), définissez res / layout / main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/border"
    android:padding="10dip" >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Hello World, SOnich"
        />
    [... more TextView ...]
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Hello World, SOnich"
        />
</LinearLayout>

et un res/drawable/border.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
   <stroke
        android:width="5dip"
        android:color="@android:color/white" />
</shape>

Signalé pour fonctionner sur un appareil en pain d'épice. Notez que vous devrez associer android:paddingle LinearLayout à la valeur de la android:widthforme / du trait. Veuillez ne pas utiliser @android:color/whitedans votre application finale mais plutôt une couleur définie par le projet.

Vous pouvez appliquer android:background="@drawable/border" android:padding="10dip"à chacun des LinearLayout à partir de votre échantillon fourni.

En ce qui concerne vos autres articles liés à l'affichage de certains cercles comme arrière-plan de LinearLayout, je joue avec les ressources dessinables Inset / Scale / Layer ( voir Ressources Drawable pour plus d'informations) pour que quelque chose fonctionne pour afficher des cercles parfaits en arrière-plan d'un LinearLayout mais a échoué en ce moment…

Votre problème réside clairement dans l'utilisation de getBorder.set{Width,Height}(100);. Pourquoi faites-vous cela dans une méthode onClick?

J'ai besoin d'informations supplémentaires pour ne pas rater le sujet: pourquoi faites-vous cela par programme? Avez-vous besoin d'un comportement dynamique? Vos tirables d'entrée sont png ou ShapeDrawable est acceptable? etc.

A suivre (peut-être demain et dès que vous apporterez plus de précisions sur ce que vous souhaitez réaliser)…

Renaud
la source
@Renaud existe-t-il un moyen de changer la couleur de la bordure de manière problématique?
user1940676
12
LinearLayoutJe ne sais pas pourquoi c'était le cas, mais quand je l'ai utilisé sur un, j'ai obtenu un remplissage solide de la couleur de la bordure, sauf si j'ai ajouté l'enfant suivant à l' shapeélément:<solid android:color="@android:color/transparent" />
dahvyd
2
Pour moi, c'était la même chose que je devais ajouter, <solid android:color="@color/lighter_gray" />sinon j'ai un fond noir
Panciz
1
Cette méthode fonctionne parfaitement; cependant, il crée deux couches "Overdraw" ce qui est vraiment mauvais pour les performances, même si vous définissez l'arrière-plan sur "null" ou "transparent". Quelqu'un peut-il suggérer un moyen de résoudre ce problème?
Sam Ramezanli
16

Étendez LinearLayout / RelativeLayout et utilisez-le directement sur le XML

package com.pkg_name ;
...imports...
public class LinearLayoutOutlined extends LinearLayout {
    Paint paint;    

    public LinearLayoutOutlined(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        setWillNotDraw(false) ;
        paint = new Paint();
    }
    public LinearLayoutOutlined(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        setWillNotDraw(false) ;
        paint = new Paint();
    }
    @Override
    protected void onDraw(Canvas canvas) {
        /*
        Paint fillPaint = paint;
        fillPaint.setARGB(255, 0, 255, 0);
        fillPaint.setStyle(Paint.Style.FILL);
        canvas.drawPaint(fillPaint) ;
        */

        Paint strokePaint = paint;
        strokePaint.setARGB(255, 255, 0, 0);
        strokePaint.setStyle(Paint.Style.STROKE);
        strokePaint.setStrokeWidth(2);  
        Rect r = canvas.getClipBounds() ;
        Rect outline = new Rect( 1,1,r.right-1, r.bottom-1) ;
        canvas.drawRect(outline, strokePaint) ;
    }

}

<?xml version="1.0" encoding="utf-8"?>

<com.pkg_name.LinearLayoutOutlined
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
    android:layout_width=...
    android:layout_height=...
   >
   ... your widgets here ...

</com.pkg_name.LinearLayoutOutlined>
Gabriel Riba
la source
34
Veuillez ne pas allouer de mémoire dans la onDraw()méthode, créer vos objets dans une init()méthode, appelée par le constructeur et les réutiliser dans la onDraw()méthode. L'allocation onDraw()(appelée 60 fois par seconde) entraîne des performances médiocres, une décharge de la batterie, etc.
Louis CAD