Android: jak narysować granicę w LinearLayout

197

Mam trzy pliki. XML, funkcja rysowania i główne działanie. Mam trochę LinearLayoutw moim pliku 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>

To jest funkcja rysowania:

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

I to jest główne działanie:

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

Program mógł narysować ramkę, ale rozmiar nie pasował LinearLayout. A kiedy kliknę LinearLayoutponownie, program ulega awarii.

Kolejna rzecz, chcę narysować dwa koła na środku LinearLayout, ale jak mogę ustalić współrzędne środkowe?

SPG
źródło

Odpowiedzi:

459

Czy naprawdę musisz to zrobić programowo?

Właśnie biorąc pod uwagę tytuł: możesz użyć ShapeDrawable jako Androida: tło…

Na przykład zdefiniujmy res/drawable/my_custom_background.xmljako:

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

i zdefiniuj androida: background = "@ drawable / my_custom_background".

Nie testowałem, ale powinno działać.

Aktualizacja:

Wydaje mi się, że lepiej jest wykorzystać siłę zasobów zasobu xml w kształcie, jeśli to odpowiada Twoim potrzebom. W projekcie „od zera” (dla Androida-8) zdefiniuj 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>

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

Zgłoszony do pracy na urządzeniu z piernika. Pamiętaj, że musisz powiązać android:paddingLinearLayout z wartością android:widthkształtu / obrysu. Proszę nie używać @android:color/whitew końcowej aplikacji, ale kolor zdefiniowany w projekcie.

Możesz złożyć podanie android:background="@drawable/border" android:padding="10dip"do każdego LinearLayout z dostarczonej próbki.

Jeśli chodzi o twoje inne posty związane z wyświetlaniem niektórych kręgów jako tła LinearLayout, gram z zasobami rysunkowymi Inset / Scale / Layer ( więcej informacji można znaleźć w Zasobach rysowalnych ), aby coś działało, aby wyświetlać idealne koła w tle LinearLayout, ale nie powiodło się w tym momencie…

Twój problem wynika wyraźnie z używania getBorder.set{Width,Height}(100);. Dlaczego robisz to w metodzie onClick?

Potrzebuję dodatkowych informacji, aby nie umknąć uwadze: dlaczego robisz to programowo? Czy potrzebujesz dynamicznego zachowania? Twoje wkładki są png lub czy ShapeDrawable jest akceptowalny? itp.

Ciąg dalszy nastąpi (może jutro i gdy tylko podasz więcej szczegółów na temat tego, co chcesz osiągnąć)…

Renaud
źródło
@Renaud czy istnieje sposób, aby problematycznie zmienić kolor obramowania?
user1940676,
12
Nie jestem pewien, dlaczego tak się stało, ale kiedy go użyłem LinearLayout, uzyskałem pełne wypełnienie z koloru obramowania, chyba że dodałem do shapeelementu następujące dziecko :<solid android:color="@android:color/transparent" />
dahvyd
2
Dla mnie było tak samo, musiałem dodać, w <solid android:color="@color/lighter_gray" />przeciwnym razie mam czarne tło
Panciz
1
Ta metoda doskonale działa; tworzy jednak dwuwarstwowy „Overdraw”, co jest naprawdę niekorzystne dla wydajności, nawet jeśli ustawisz tło na „null” lub „transparent”. Czy ktoś może zaproponować sposób rozwiązania tego problemu?
Sam Ramezanli,
16

Rozszerz LinearLayout / RelativeLayout i użyj go bezpośrednio w pliku 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
źródło
34
Proszę nie przydzielać pamięci w onDraw()metodzie, tworzyć obiekty w init()metodzie wywoływanej przez konstruktora i ponownie wykorzystywać je w onDraw()metodzie. Przydzielanie onDraw()(zwane 60 razy na sekundę) prowadzi do słabej wydajności, wyczerpania baterii itp.
Louis CAD