217 votes

Android : comment dessiner une bordure à un LinearLayout

J'ai trois fichiers. Le XML, la fonction de dessin et l'activité principale. J'ai des LinearLayout dans 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>

Il s'agit de la fonction de tirage au sort :

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 pourrait dessiner une bordure mais la taille ne correspond pas à la LinearLayout . Et quand je clique sur le LinearLayout Encore une fois, le programme s'est écrasé.

Je veux aussi dessiner deux cercles au centre de l'image. LinearLayout mais comment trouver les coordonnées du centre ?

498voto

Renaud Points 2779

Avez-vous vraiment besoin de faire cela de manière programmatique ?

Juste en considérant le titre : Vous pourriez utiliser un ShapeDrawable comme Android:background

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

<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 cela devrait fonctionner.

Mise à jour :

Je pense qu'il est préférable de tirer parti de la puissance des ressources extractibles de la 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>

Il a été signalé qu'il fonctionne sur un appareil gingerbread. Notez que vous aurez besoin de relier android:padding de la LinearLayout à la android:width la valeur de la forme/du trait. N'utilisez pas @android:color/white dans votre application finale mais plutôt une couleur définie par le projet.

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

Pour ce qui est de vos autres messages concernant l'affichage de cercles en tant qu'arrière-plan du LinearLayout, je joue avec les ressources dessinables Inset/Scale/Layer ( voir Ressources dessinables pour plus d'informations) pour obtenir quelque chose de fonctionnel pour afficher des cercles parfaits en arrière-plan d'un LinearLayout mais sans succès pour le moment

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

J'ai besoin d'informations supplémentaires pour ne pas passer à côté de l'essentiel : pourquoi faites-vous cela par programme ? Avez-vous besoin d'un comportement dynamique ? Vos drawables d'entrée sont png ou ShapeDrawable est acceptable ? etc.

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

0 votes

0 votes

@Renaud existe-t-il un moyen de changer la couleur de la bordure sans problème ?

0 votes

@user1940676 C'est peut-être possible en récupérant la ressource ShapeDrawable, en obtenant la peinture (getPaint), puis en utilisant setColor etc. mais je n'ai jamais essayé

17voto

Gabriel Riba Points 2602

Étendre LinearLayout/RelativeLayout et l'utiliser 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>

37 votes

S'il vous plaît, n'allouez pas de mémoire dans onDraw() créez vos objets dans un init() appelée par le constructeur et les réutiliser dans la méthode onDraw() méthode. L'allocation dans onDraw() (appelé 60 fois par seconde) entraîne des performances médiocres, une usure de la batterie, etc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X