Czy istnieje prosty sposób na dodanie ramki do górnej i dolnej części widoku Androida?


407

Mam TextView i chciałbym dodać czarną ramkę wzdłuż górnej i dolnej granicy. Próbowałem dodać android:drawableTopi android:drawableBottomdo TextView, ale to spowodowało, że cały widok stał się czarny.

<TextView
    android:background="@android:color/green"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:drawableTop="@android:color/black"
    android:drawableBottom="@android:color/black"
    android:text="la la la" />

Czy istnieje sposób na łatwe dodanie górnej i dolnej ramki do widoku (w szczególności TextView) w Androidzie?


2
Zaskakujące, że nikt nie wspominał o dividerVertical ! To jest rzecz stworzona przez Androida, aby osiągnąć, no cóż, pionowe dzielniki. CO nie będzie łatwiejsze i wszystko robisz w panelu WYSIWYG „Projektowanie” w Android Studio.
Fattie

note dividerVertical został zaimplementowany w API 11.
JPM

1
Może możesz pokazać, jak korzystać z dividerVertical?
androidguy

Odpowiedzi:


430

W Androidzie 2.2 możesz wykonać następujące czynności.

Utwórz rysunkowy xml, taki jak /res/drawable/textlines.xml i przypisz go jako właściwość tła TextView.

<TextView
android:text="My text with lines above and below"
android:background="@drawable/textlines"
/>

/res/drawable/textlines.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
      <shape 
        android:shape="rectangle">
            <stroke android:width="1dp" android:color="#FF000000" />
            <solid android:color="#FFDDDDDD" />

        </shape>
   </item>

   <item android:top="1dp" android:bottom="1dp"> 
      <shape 
        android:shape="rectangle">
            <stroke android:width="1dp" android:color="#FFDDDDDD" />
            <solid android:color="#00000000" />
        </shape>
   </item>

</layer-list>

Wadą tego jest to, że musisz określić nieprzezroczysty kolor tła, ponieważ folie nie będą działać. (Przynajmniej myślałem, że tak, ale się myliłem). W powyższym przykładzie widać, że jednolity kolor pierwszego kształtu #FFdddddd jest kopiowany w kolorze obrysu 2. kształtu.


11
Zobacz także to rozwiązanie, które działa również dla TextViews, jeśli chcesz mieć wokół siebie ramkę: stackoverflow.com/questions/3263611/...
emmby

26
Spróbuj użyć, android:color="@null"aby uniknąć nieprzezroczystego problemu z tłem.
Matt Briançon,

@emmby: podczas testowania tego kodu na tablecie renderowanie na ekranie zajmuje trochę czasu, a po przewinięciu wyświetlają się 1-sekundowe ramki
Chetan 3'12

5
Sztuczka dla Androida: color = "@ null" nie zrobiła tego dla mnie, aby zachować przezroczystość i po prostu wyświetlić ramkę po jednej stronie widoku. Odpowiedź od user1051892 poniżej wykonała zadanie!
Rick Pastoor

8
To rozwiązanie stworzyło również granicę po lewej i prawej stronie - choć cieńsze.
AlikElzin-kilaka

279

Użyłem lewy, aby ramka była wyświetlana poza kontenerem. W przypadku tej sztuczki rysowana jest tylko linia, aby pokazać tło widoku podstawowego.

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:bottom="1dp"
        android:left="-2dp"
        android:right="-2dp"
        android:top="-2dp">
        <shape android:shape="rectangle" >
            <stroke
                android:width="1dp"
                android:color="#FF000000" />

            <solid android:color="#00FFFFFF" />

            <padding android:left="10dp"
                android:right="10dp"
                android:top="10dp"
                android:bottom="10dp" />
        </shape>
    </item>

</layer-list>

3
Działa to dla mnie świetnie, z kilkoma poprawkami, aby linia była nieco cieńsza.
Jeff

1
Bardzo fajna sztuczka, chociaż może być ładniejsza, jeśli nie musimy oszukiwać komputera, aby załatwić sprawę.
Yukio Fukuzawa,

ładnie wykonane! to, co powinieneś obejrzeć to lewy, górny, prawy, dolny element przedmiotu - (szerokość obrysu) dp
asakura89

Nie
pokazałem

1
Ładnie wykonane, działało na przezroczystym tle. Testowane w 2.2 i 4.4.2. Powinny obejmować wszystko pomiędzy :)
HumaN

97

Opcja 1: kształt rysowany

Jest to najprostsza opcja, jeśli chcesz obramować układ lub widok, w którym możesz ustawić tło. Utwórz plik XML w drawablefolderze, który wygląda mniej więcej tak:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <solid android:color="#8fff93" />

    <stroke
        android:width="1px"
        android:color="#000" />

</shape>

Możesz usunąć, solidjeśli nie chcesz wypełnienia. Zestaw background="@drawable/your_shape_drawable"w twoim układzie / widoku.

Opcja 2: Widok tła

Oto mała sztuczka, której użyłem w RelativeLayout. Zasadniczo masz czarny kwadrat pod widokiem, który chcesz nadać ramce, a następnie nadaj temu widokowi trochę wypełnienia (nie marginesu!), Aby czarny kwadrat był widoczny na krawędziach.

Oczywiście działa to poprawnie tylko wtedy, gdy widok nie ma żadnych przezroczystych obszarów. Jeśli tak, polecam napisać niestandardowy, BorderViewktóry tylko rysuje granicę - powinien to być tylko kilkadziesiąt linii kodu.

<View
    android:id="@+id/border"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBottom="@+id/image"
    android:layout_alignLeft="@+id/image"
    android:layout_alignRight="@+id/image"
    android:layout_alignTop="@+id/main_image"
    android:background="#000" />

<ImageView
    android:id="@+id/image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_...
    android:padding="1px"
    android:src="@drawable/..." />

Jeśli zastanawiasz się, to czyni pracę z adjustViewBounds=true. Jednak to nie działa, jeśli chcesz mieć tło w całości RelativeLayout, ponieważ istnieje błąd, który powstrzymuje Cię od wypełnienia RelativeLayoutznakiem View. W takim przypadku polecam Shapewyciągnąć.

Opcja 3: 9 łatek

Ostatnią opcją jest skorzystanie z 9-patcha, który można wyciągnąć w następujący sposób:

Możesz go użyć w dowolnym widoku, w którym możesz ustawić android:background="@drawable/...". I tak, to musi być 6x6 - próbowałem 5x5 i to nie działało.

Wadą tej metody jest to, że nie możesz bardzo łatwo zmieniać kolorów, ale jeśli chcesz fantazyjne obramowania (np. Tylko obramowanie u góry iu dołu, jak w tym pytaniu), możesz nie być w stanie zrobić ich z Shaperysowalnym , co nie jest zbyt potężne.

Opcja 4: Dodatkowe widoki

Zapomniałem wspomnieć o tej naprawdę prostej opcji, jeśli chcesz tylko ramki powyżej i poniżej widoku. Możesz umieścić swój widok w pionie LinearLayout(jeśli jeszcze nie jest), a następnie dodać puste Views powyżej i poniżej tak:

<View android:background="#000" android:layout_width="match_parent" android:layout_height="1px"/>

4
9 łatek i rysowalny kształt są w porządku, ale odradzam dodawanie widoków lub widoków obrazów, aby rozwiązać taki problem. Powodem jest to, że powinieneś usunąć jak najwięcej takich <elementów> ze swoich układów, aby poprawić przerysowanie układu i animację. Rozebrałbym je od razu i zaimplementowałem niektóre podobne do opcji 1 lub 2.
Emile,

2
@Emile To prawda, ale jeśli używasz niestandardowego widoku listy, który nie obsługuje dzielników, prosty widok jest w porządku. Wpływ na wydajność jest bliski zeru, zwłaszcza jeśli na pewno utrzymasz głębię układu. Pozwala to również uniknąć błędów związanych z dzielnikami ListView na różnych urządzeniach (widziałem niektóre urządzenia, które ignorują tę właściwość).
Tom

Możesz również użyć wydajnego wzorca widoku z widokami list, aby zmniejszyć liczbę wywołań funkcji findViewByID, co często jest przyczyną niskiej wydajności listy.
Emile,

W iOS masz tylko jeden sposób, aby to zrobić. Na Androidzie powinieneś przetestować co najmniej cztery, w moim przypadku była to opcja 4. Czasami rysunki jako tło zawieszają się, aby renderować, bądź tego świadomy.
Ratata Tata

1
Dlaczego Android nie miał najłatwiejszego rozwiązania dla takich rzeczy? jak w innym języku, takim jak HTML, CSS lub coś w JavaFX, WPF ......
Asif Mushtaq

95

Aby dodać 1dpbiałą ramkę tylko u dołu i mieć przezroczyste tło, możesz skorzystać z poniższych, co jest prostsze niż większość odpowiedzi tutaj.

Dla tego TextViewlub innego widoku dodaj:

android:background="@drawable/borderbottom"

A w drawablekatalogu dodaj następujący kod XML o nazwieborderbottom.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:top="-2dp" android:left="-2dp" android:right="-2dp">
        <shape android:shape="rectangle">
            <stroke android:width="1dp" android:color="#ffffffff" />
            <solid android:color="#00000000" />
        </shape>
    </item>
</layer-list>

Jeśli chcesz mieć ramkę u góry, zmień android:top="-2dp"naandroid:bottom="-2dp"

Kolor nie musi być biały, a tło nie musi być przezroczyste.

solidNie mogą być wymagane elementem. Będzie to zależeć od twojego projektu (dzięki V. Kalyuzhnyu).

Zasadniczo ten plik XML utworzy ramkę przy użyciu kształtu prostokąta, ale następnie wypchnie górną, prawą i lewą stronę poza obszar renderowania dla kształtu. Pozostawia to tylko dolną ramkę.


8
To najlepsze rozwiązanie, ponieważ nie tworzy overdraw jak inne
Greg Ennis

Czy istnieje powód, dla którego ujemne pozycje są dwa razy większe niż uderzenie przy ( -2dpvs 1dp)? Wydaje się działać, gdy są równe pod względem ilości ( -1i 1).
Denis Kniazhev,

@DenisKniazhev: Podczas korzystania -2dpwynik był zawsze czysty. Myślę, że był przypadek testowy, w którym wynik nie był czysty. Nie pamiętam, czy był to ekran o niskiej lub wysokiej gęstości, czy nawet starsza wersja Androida (może 2.x).
Tigger,

Ciekawy. Czy wiesz, czy jest to ogólny przypadek, na przykład jeśli 4dpużyję szerokości skoku, czy powinienem użyć -8dpdo pozycjonowania?
Denis Kniazhev,

1
@DenisKniazhev: (z pamięci) wyglądało to jak obliczenie zmiennoprzecinkowe, które było od małego do dużego lub małego. Oznacza to, że wartość -5dpbyłaby wszystkim, co jest potrzebne przy wartości szerokości równej 4pd. Po prostu musiał być nieco większy, aby przekroczyć niedokładność wartości zmiennoprzecinkowej.
Tigger,

36

Aktualnie akceptowana odpowiedź nie działa. W wyniku wygładzania tworzy cienkie pionowe ramki po lewej i prawej stronie widoku.

Ta wersja działa idealnie. Umożliwia także niezależne ustawianie szerokości ramek, a także dodawanie ramek po lewej / prawej stronie, jeśli chcesz. Jedyną wadą jest to, że NIE obsługuje przezroczystości.

Utwórz rysunkowy xml o nazwie /res/drawable/top_bottom_borders.xmlz poniższym kodem i przypisz go jako właściwość tła TextView .

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#DDDD00" /> <!-- border color -->
        </shape>
    </item>

    <item
        android:bottom="1dp" 
        android:top="1dp">   <!-- adjust borders width here -->
        <shape android:shape="rectangle">
            <solid android:color="#FFFFFF" />  <!-- background color -->
        </shape>
    </item>
</layer-list>

Testowane na Androidzie KitKat przez Marshmallow


Jak zrobić wnętrze przezroczyste?
Hitesh Sahu,

1
@HiteshSahu Myślę, że wadą tego jest to, że musiałbyś dopasować tło układu do tła widżetu tutaj
chntgomez

35

Chciałem więc zrobić coś nieco innego: TYLKO ramkę na dole, aby zasymulować dzielnik ListView. Zmodyfikowałem odpowiedź Piet Delport i otrzymałem to:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
   <item>
      <shape 
        android:shape="rectangle">
            <solid android:color="@color/background_trans_light" />    

        </shape>
   </item>

    <!-- this mess is what we have to do to get a bottom border only. -->
   <item android:top="-2dp"
         android:left="-2dp"
         android:right="-2dp"
         android:bottom="1px"> 
      <shape 
        android:shape="rectangle">    
            <stroke android:width="1dp" android:color="@color/background_trans_mid" />
            <solid android:color="@null" />
        </shape>
   </item>

</layer-list>

Uwaga: użycie px zamiast dp, aby uzyskać dokładnie 1 dzielnik pikseli (niektóre DPI telefonu powodują zniknięcie linii 1dp).


2
drogi! Jaka jest wartość "@color/background_trans_light"?
Shajeel Afzal

Na zdrowie @ phreakhead, to faktycznie działa dla mnie! Brak górnej, lewej lub prawej granicy. Dokładnie to, czego potrzebowałem, dzięki!
shanehoban

2
Czy możesz wyjaśnić, dlaczego po włożeniu -2dp znika, a po włożeniu -1dp jest nadal widoczny? Dzięki!
Francisco Romero,

9

Tak jak powiedział @Nic Hubbard, istnieje bardzo łatwy sposób na dodanie linii granicznej.

<View
    android:layout_width="match_parent"
    android:layout_height="2dp"
    android:background="#000000" >
</View>

Możesz zmienić wysokość i kolor tła na cokolwiek chcesz.


8

Moje odpowiedzi są oparte na wersji @Emile, ale używam przezroczystego koloru zamiast jednolitego.
Ten przykład narysuje dolną granicę 2dp.

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <shape android:shape="rectangle" >
            <stroke  android:width="2dp"
                     android:color="#50C0E9" />
            <solid android:color="@android:color/transparent" />
        </shape>
    </item>
    <item  android:bottom="2dp" >
        <shape android:shape="rectangle" >
            <stroke  android:width="2dp"
                     android:color="@color/bgcolor" />
            <solid android:color="@android:color/transparent" />
        </shape>
    </item>
</layer-list>

@ color / bgcolor to kolor tła, na którym narysujesz widok z ramką.

Jeśli chcesz zmienić położenie granicy, zmień przesunięcie jednym z:

android:bottom="2dp"
android:top="2dp"
android:right="2dp"
android:left="2dp"

lub połącz je, aby mieć 2 lub więcej ramek:

android:bottom="2dp" android:top="2dp"

7

Możesz także zawinąć widok w FrameLayout, a następnie ustawić kolor tła i dopełnienie ramki do tego, co chcesz; jednak widok tekstu ma domyślnie „przezroczyste” tło, dlatego należy zmienić również kolor tła widoku tekstu.


Dość proste. Kontrolujesz rozmiar i kierunek konturów na marginesach wewnętrznego widoku. Dzięki.
Scott Biggs,

5

Dlaczego po prostu nie utworzyć widoku wysokiej rozdzielczości 1dp z kolorem tła? Następnie można go łatwo ustawić w dowolnym miejscu.


4

Aby dodać moje rozwiązanie do listy ...

Chciałem półprzezroczystą dolną ramkę, która rozciąga się poza pierwotny kształt (więc półprzezroczysta ramka znajdowała się poza prostokątem nadrzędnym).

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
  <item>
    <shape android:shape="rectangle" >      
      <solid android:color="#33000000" /> <!-- Border colour -->
    </shape>
  </item>
  <item  android:bottom="2dp" >
    <shape android:shape="rectangle" >     
      <solid android:color="#164586" />
    </shape>
  </item>
</layer-list>

Co daje mi;

wprowadź opis zdjęcia tutaj


4

Aby to zmienić:

<TextView
    android:text="My text"
    android:background="@drawable/top_bottom_border"/>

Wolę to podejście w „drawable / top_bottom_border.xml”:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <gradient
                android:angle="270"
                android:startColor="#000"
                android:centerColor="@android:color/transparent"
                android:centerX="0.01" />
        </shape>
    </item>
    <item>
        <shape>
            <gradient
                android:angle="90"
                android:startColor="#000"
                android:centerColor="@android:color/transparent"
                android:centerX="0.01" />
        </shape>
    </item>
</layer-list>

Powoduje to, że obramowania, a nie prostokąt, który pojawi się, jeśli tło ma kolor.


3

Najpierw utwórz plik xml z zawartością pokazaną poniżej i nazwij go border.xml i umieść go w folderze układu w katalogu res

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <stroke android:width="1dp" android:color="#0000" />
    <padding android:left="0dp" android:top="1dp" android:right="0dp"
        android:bottom="1dp" />
</shape>

Następnie użyj kodu

TextView tv = (TextView)findElementById(R.id.yourTextView);
tv.setBackgroundResource(R.layout.border);

Spowoduje to utworzenie czarnej linii na górze i na dole TextView.


Tak, zadziała, sprawdziłem. Przycisk przycisk = (przycisk) findViewById (przycisk R.id.); button.setBackgroundResource (R.layout.border);
Nikhil Dinesh

Użyłem czarnego koloru w powyższym pliku xml, twój kolor tła może być czarny, spróbuj użyć innego koloru. Na pewno zadziała <kodowanie wersji x? = "1.0" = "UTF-8"?> <Kształt xmlns: android = " schemas.android.com/apk/res/android "> <solid android: color = "# 474848 "/> <stroke android: width =" 1dp "android: color =" # ffff00 "/> <padding android: left =" 1dp "android: top =" 1dp "android: right =" 1dp "android: bottom =" 1dp "/> </shape>
Nikhil Dinesh

1
Nie działało dla mnie. Linia graniczna została namalowana na środku widoku tekstu - w poziomie.
AlikElzin-kilaka

3

Zapisz poniżej kodu

<View
    android:layout_width="wrap_content"
    android:layout_height="2dip"
    android:layout_below="@+id/topics_text"
    android:layout_marginTop="7dp"
    android:layout_margin="10dp"
    android:background="#ffffff" />

2

Oto sposób na osiągnięcie tego.

    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item>
            <shape android:shape="rectangle">
                <stroke
                    android:width="1dp"
                    android:color="@color/grey_coaching_text" />
            </shape>
        </item>

        <item
            android:bottom="1dp"
            android:top="1dp">
            <shape android:shape="rectangle">
                <solid android:color="@color/white" />
            </shape>
        </item>
    </layer-list>

Pierwszy element do obrysu i drugi do jednolitego tła. Ukrywanie lewej i prawej granicy.


2

Najprostszym sposobem dodania obramowań w celu wstawienia obramowań za pomocą InsetDrawable, następujące pokaże tylko górną ramkę:

<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:insetBottom="-2dp"
    android:insetLeft="-2dp"
    android:insetRight="-2dp">
    <shape android:shape="rectangle">

        <solid android:color="@color/light_gray" />
        <stroke
            android:width=".5dp"
            android:color="@color/dark_gray" />
    </shape>
</inset>

2

Dodaj plik do res / drawable

<?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:left="-2dp" android:right="-2dp">
            <shape android:shape="rectangle">
                <stroke
                    android:width="1dp"
                    android:color="#000000" />
            </shape>
        </item>
    </layer-list>

Dodaj link do tego pliku do właściwości tła


1

Spróbuj owinąć obraz liniowym układem i ustaw jego tło na odpowiedni kolor obramowania wokół tekstu. Następnie ustaw dopełnienie w widoku tekstu na grubość, którą chcesz dla swojej ramki.


1

Możesz także skorzystać z 9 ścieżek, aby wykonać swoją pracę. Utwórz go, aby kolorowy piksel nie zwielokrotniał się na wysokości, a tylko przezroczysty piksel.


1
<shape xmlns:android="http://schemas.android.com/apk/res/android">

<solid android:color="@color/light_grey1" />
<stroke
    android:width="1dip"
    android:color="@color/light_grey1" />

<corners
    android:bottomLeftRadius="0dp"
    android:bottomRightRadius="0dp"
    android:topLeftRadius="5dp"
    android:topRightRadius="5dp" />

    </shape>

1

Po prostu dodaj widoki u góry iu dołu View

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/your_color"
        app:layout_constraintBottom_toTopOf="@+id/textView"
        app:layout_constraintEnd_toEndOf="@+id/textView"
        app:layout_constraintStart_toStartOf="@+id/textView" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:gravity="center"
        android:text="Testing"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/your_color"
        app:layout_constraintEnd_toEndOf="@+id/textView"
        app:layout_constraintStart_toStartOf="@+id/textView"
        app:layout_constraintTop_toBottomOf="@+id/textView" />

</android.support.constraint.ConstraintLayout>

0
// Just simply add border around the image view or view

<ImageView
                android:id="@+id/imageView2"
                android:layout_width="90dp"
                android:layout_height="70dp"
                android:layout_centerVertical="true"
                android:layout_marginRight="10dp"
                android:layout_toLeftOf="@+id/imageView1"
                android:background="@android:color/white"
                android:padding="5dip" />

// After that dynamically put color into your view or image view object

objView.setBackgroundColor(Color.GREEN);

//VinodJ/Abhishek

-1
<TextView
    android:id="@+id/textView3"
    android:layout_width="match_parent"
    android:layout_height="2dp"
    android:background="#72cdf4"
    android:text=" aa" />

Po prostu dodaj ten TextView poniżej tekstu, w którym chcesz dodać ramkę


-1

Aby wymusić odpowiedzi @phreakhead i user1051892 , <item android:bottom|android:left|android:right|android:top>jeśli negatywne, muszą być większe niż <stroke android:width>. Jeśli nie, obraz przedmiotu zostanie pomieszany z obrazem obrysu i możesz pomyśleć, że te wartości nie działają.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.