Otwarte obrysy Androida?

95

Czy można utworzyć obiekt kształtu Androida z obrysem tylko z niektórych stron?

Np. Mam:

<stroke 
 android:width="3dip" 
 android:color="#000000"
    android:dashWidth="10dip" 
    android:dashGap="6dip" />

Który jest podobny do tego CSS:

border: 3px dashed black;

Jak ustawić pociągnięcie tylko z jednej strony? Oto jak zrobiłbym to w CSS:

border-left: 3px dashed black;

Jak to zrobić w Android XML?

Reed Morse
źródło

Odpowiedzi:

127

Dzięki temu osiągnąłem dobre rozwiązanie:

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

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- This is the line -->
    <item android:top="-1dp" android:right="-1dp" android:left="-1dp">
      <shape>
            <solid android:color="@android:color/transparent" />
            <stroke android:width="1dp" android:color="#ffffff" />
      </shape>
    </item>

</layer-list>

Działa to dobrze, jeśli potrzebujesz przezroczystego tła, ale wciąż otwartego koloru obrysu (w moim przypadku potrzebowałem tylko dolnej linii). Jeśli potrzebujesz koloru tła, możesz dodać jednolity kolor kształtu, jak w odpowiedzi Maragues.

EDYCJA 1

Czasami, w przypadku urządzeń o wysokiej gęstości, używanie niskich wartości spadku może kończyć się bardzo cienkimi lub niewidocznymi pociągnięciami lub odległościami. Może się to zdarzyć również podczas ustawiania dzielników ListView.

Najprostszym obejściem jest użycie odległości 1 piksela zamiast 1 dp. Dzięki temu linia będzie zawsze widoczna przy wszystkich gęstościach. Najlepszym rozwiązaniem byłoby utworzenie zasobów wymiarów dla każdej gęstości, aby uzyskać najlepszy rozmiar dla każdego urządzenia.

Edytuj 2

Zabawne, ale próbowałem tego użyć 6 lat później i nie mogę uzyskać dobrego wyniku na urządzeniach Lollipop.

Prawdopodobnie obecnym rozwiązaniem jest użycie 9 łatek. Android po tylu latach powinien był łatwo rozwiązać ten problem.

htafoya
źródło
To również zadziałało dla mnie, ale nie wiem dokładnie, dlaczego musiałem użyć -2dp zamiast -1dp. Gdybym użył tego drugiego, nadal widziałem cienką linię.
Edu Zamora
1
@EduZamora tak, wygląda na to, że dla urządzeń o dużej gęstości -1dp nie działa zgodnie z oczekiwaniami
htafoya
Dostaję też obramowanie ze wszystkich stron, ale nie tylko dolną.
Cheok Yan Cheng
@YanChengCHEOK spróbuj 1px zamiast 1dp.
htafoya
@htafoya to genialne rozwiązanie. Dzięki!
abriggs
53

Wiem, że to pytanie zostało wysłane dawno temu, więc odpowiedź nie zostanie użyta przez osobę, która je opublikowała, ale może pomóc innym.

 <?xml version="1.0" encoding="UTF-8"?>
    <!-- inset is used to remove border from top, it can remove border from any other side-->
    <inset xmlns:android="http://schemas.android.com/apk/res/android"
        android:insetTop="-2dp"
        >
    <shape xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rectangle">
        <stroke android:width="1dp" android:color="#b7b7b7" />
        <corners android:bottomRightRadius="5dp"  android:bottomLeftRadius="5dp"/>

        <solid android:color="#454444"/>
    </shape>
    </inset>

Użyj insettagu i podaj ujemną wartość krawędzi bocznej, którą chcesz usunąć.

Możliwe wartości to:

android:insetTop="-1dp" android:insetBottom="-1dp" android:insetLeft="-1dp" android:insetRight="-1dp"

Nirmal Dhara
źródło
Tak, i nie rób tego, co zrobiłem i spróbuj umieścić wstawkę atr w tagu obrysu bez czytania reszty odpowiedzi! (dzięki za odpowiedź BTW OP. Idealne rozwiązanie)
Kiran
elegancki! Uwielbiam to rozwiązanie
Hao Qi
41

Rozwiązałem to używając warstwy listy, łączącej dwa kształty, z których jeden o wysokości 1dp umieszczony na dole

optionscreen_bottomrectangle.xml:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- This is the line -->
<item>
      <shape>
            <solid android:color="#535353" />
      </shape>
</item>
<!-- This is the main color -->
<item android:bottom="1dp">
     <shape>
           <solid android:color="#252525" />
     </shape>
</item>
</layer-list>

Następnie w pliku layout / main.xml

<TextView
    android:id="@+id/bottom_rectangle"
    android:background="@drawable/optionscreen_bottomrectangle"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:layout_below="@id/table_options"
    android:layout_above="@id/exit_bar"/>

Wypełnia lukę między table_options i exit_bar tłem, a tuż przed exit_bar drukuje linię 1dp. To załatwiło sprawę dla mnie, mam nadzieję, że pomoże to komuś innemu.

Odpowiedź została zmieniona w celu umieszczenia warstw we właściwej kolejności. Dzięki Alex!

Maragues
źródło
Może być przydatne nie publikowanie odpowiedzi, jeśli naprawdę chcesz uzyskać odpowiedź samodzielnie. Kiedy inni deweloperzy widzą, że jest już odpowiedź (chociaż w tym przypadku tak naprawdę nie jest), nie są tak skłonni do odpowiedzi.
MrSnowflake
31

Kolejne podejście do innych odpowiedzi wykorzystujących zamiast tego dopełnienie. Ten mały skrawek tworzy granicę na górze i na dole.

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- This is the line -->
    <item>
          <shape>
                <padding android:left="0dp" android:top="1dp" android:right="0dp" android:bottom="1dp"/>
                <solid android:color="#898989" />
          </shape>
    </item>
    <!-- This is the main color -->
    <item>
         <shape>
             <solid android:color="#ffffff" />
         </shape>
    </item>
</layer-list>
ug_
źródło
4
To zdecydowanie najlepsza odpowiedź, jeśli potrzebujesz zaokrąglonych rogów.
MacKinley Smith
Ten też bardzo mi pomógł. Proszę, spróbuj i zagłosuj za
Boy
@ug_ Myślę, że to najlepsze podejście. Działa idealnie, dzięki
Lalit Sharma
Pracuje. Wygląda zupełnie źle w okienku podglądu Android Studio (v1.1), ale na urządzeniu jest w porządku.
Murat Ögat
26

Odpowiedź @ Maragues jest odwrotna, ponieważ rysunki na liście warstw rysują się od góry do dołu (co oznacza, że ​​ostatni element na liście jest rysowany na górze):

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- This is the line -->
<item>
      <shape>
            <solid android:color="#535353" />
      </shape>
</item>
<!-- This is the main color -->
<item android:bottom="1dp">
     <shape>
           <solid android:color="#252525" />
     </shape>
</item>

</layer-list>

Spowoduje to efektywne wypełnienie kształtu kolorem linii, a następnie narysowanie na nim koloru tła, pozostawiając ostatnie 1 dp przezroczyste, aby kolor linii był widoczny.

Alex Pretzlav
źródło
2
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >


<item>
    <shape android:shape="rectangle" >
        <stroke  android:width="2dp"
                 android:color="#BBBBBB" />
        <solid android:color="@android:color/transparent" />
    </shape>
</item>
<item  android:bottom="2dp" >
    <shape android:shape="rectangle" >
        <stroke  android:width="2dp"
                 android:color="@color/main_background_color" />
        <solid android:color="@android:color/transparent" />
    </shape>
</item>

słoneczny
źródło
2

Użyłem następującego kodu.

<?xml version="1.0" encoding="UTF-8"?>
<!-- inset is used to remove border from top, it can remove border from any other side-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:insetTop="-2dp" android:insetLeft="-2dp" android:insetRight="-2dp"
    >
    <shape xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rectangle">
        <stroke android:width="1dp" android:color="@color/colorPrimary" />
        <solid android:color="#0000"/>
        <padding android:left="2dp" android:top="2dp" android:bottom="2dp" android:right="2dp"/>
    </shape>
</inset>
Ken W.
źródło
0

Proste i wydajne

Aby mieć przejrzysty widok i wszystko, co jest na zewnątrz, ma nakładkę w jakimś kolorze, możesz stworzyć widoki, które obejmują widok środkowy, bez wkraczania widoków zewnętrznych na widok środkowy .

W ten sposób unikniesz konieczności rysowania zewnętrznego układu i masz większą kontrolę nad odległościami widoków bez konieczności wykonywania obliczeń w czasie wykonywania.

<androidx.constraintlayout.widget.ConstraintLayout .. >

    <View
        android:id="@+id/center"
        android:layout_width="100dp"
        android:layout_height="100dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:background="@color/transparent"/>

   <View
        android:id="@+id/left_overlay"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/center"
        app:layout_constraintTop_toBottomOf="@id/top_overlay"
        app:layout_constraintBottom_toTopOf="@id/bottom_overlay"
        android:background="@color/black"
        android:alpha="0.5"
        />

    <View
        android:id="@+id/right_overlay"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintLeft_toRightOf="@id/center"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/top_overlay"
        app:layout_constraintBottom_toTopOf="@id/bottom_overlay"
        android:background="@color/black"
        android:alpha="0.5"
        />

    <View
        android:id="@+id/top_overlay"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/center"
        android:background="@color/black"
        android:alpha="0.5"
        />

    <View
        android:id="@+id/bottom_overlay"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/center"
        android:background="@color/black"
        android:alpha="0.5"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

GL

Braian Coronel
źródło