Android: cómo dibujar un borde a un diseño lineal

197

Tengo tres archivos El XML, la función de dibujo y la actividad principal. Tengo algunos LinearLayouten mi archivo 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>

Esta es la función de dibujar:

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);
    }
}

Y esta es la actividad principal:

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);
        }
    });       
}

El programa podría llamar la frontera, pero el tamaño no encajaba en el LinearLayout. Y cuando hago clic de LinearLayoutnuevo, el programa se bloquea.

Otra cosa, quiero dibujar dos círculos en el centro de la LinearLayout, pero ¿cómo podría averiguar las coordenadas del centro?

SPG
fuente

Respuestas:

460

¿Realmente necesitas hacer eso programáticamente?

Solo considerando el título: podría usar un ShapeDrawable como Android: fondo ...

Por ejemplo, definamos res/drawable/my_custom_background.xmlcomo:

<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>

y defina android: background = "@ drawable / my_custom_background".

No lo he probado pero debería funcionar.

Actualizar:

Creo que es mejor aprovechar el poder de recursos dibujables de la forma xml si eso se ajusta a sus necesidades. Con un proyecto "desde cero" (para Android-8), defina 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>

y 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>

Reportado para trabajar en un dispositivo de pan de jengibre. Tenga en cuenta que deberá relacionar android:paddingLinearLayout con el valor de la android:widthforma / trazo. Por favor, no use@android:color/white en su aplicación final, sino más bien un color definido por el proyecto.

Puede aplicar android:background="@drawable/border" android:padding="10dip"a cada uno de los LinearLayout de su muestra proporcionada.

En cuanto a sus otras publicaciones relacionadas con la visualización de algunos círculos como fondo de LinearLayout, estoy jugando con recursos extraíbles de Inset / Scale / Layer ( consulte Recursos extraíbles para obtener más información) para obtener algo que funcione para mostrar círculos perfectos en el fondo de un LinearLayout pero falló En el momento…

Su problema reside claramente en el uso de getBorder.set{Width,Height}(100);. ¿Por qué haces eso en un método onClick?

Necesito más información para no perder el punto: ¿por qué haces eso programáticamente? ¿Necesitas un comportamiento dinámico? ¿Tus elementos de entrada son png o ShapeDrawable es aceptable? etc.

Continuará (tal vez mañana y tan pronto como proporcione más precisiones sobre lo que desea lograr) ...

Renaud
fuente
@Renaud, ¿hay alguna forma de cambiar el color del borde de forma problemática?
user1940676
12
No estoy seguro de por qué fue así, pero cuando utilicé esto en un LinearLayoutcolor de borde, obtuve un relleno sólido, a menos que agregue el siguiente shapeelemento secundario al elemento:<solid android:color="@android:color/transparent" />
dahvyd
2
Para mí fue lo mismo que tuve que agregar un, de lo <solid android:color="@color/lighter_gray" />contrario obtuve un fondo negro
Panciz
1
Este método funciona perfectamente; sin embargo, crea un "Sobregiro" de dos capas que es realmente malo para el rendimiento, incluso si configura el fondo en "nulo" o "transparente". ¿Alguien puede sugerir una forma de solucionar este problema?
Sam Ramezanli
16

Extienda LinearLayout / RelativeLayout y úselo directamente en el 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
fuente
34
Por favor, no asigne memoria en el onDraw()método, cree sus objetos en un init()método, llamado por el constructor y reutilícelos en el onDraw()método. La asignación onDraw()(llamada 60 veces por segundo) conduce a un bajo rendimiento, descarga de batería, etc.
Louis CAD