Traço Android aberto?

93

É possível criar um objeto de forma Android com traço apenas em alguns lados?

Por exemplo, eu tenho:

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

Que é semelhante a este CSS:

border: 3px dashed black;

Como posso definir o traço em apenas um lado? É assim que eu faria em CSS:

border-left: 3px dashed black;

Como você faz isso no Android XML?

Reed Morse
fonte

Respostas:

126

Eu consegui uma boa solução com este:

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

Isso funciona bem no caso de você precisar de um fundo transparente, mas ainda de uma cor de traço aberta (no meu caso, eu só precisava de uma linha de fundo). Se precisar de uma cor de fundo, você pode adicionar uma cor de forma sólida como na resposta de Maragues.

EDITAR 1

Às vezes, para dispositivos de alta densidade, o uso de valores de mergulho baixos pode resultar em cursos ou distâncias muito finas ou invisíveis. Isso pode acontecer com você também ao definir os divisores ListView.

A solução mais simples é usar uma distância de 1px em vez de 1dp. Isso tornará a linha sempre visível em todas as densidades. A melhor solução seria criar recursos de dimensão para cada densidade, para obter o melhor tamanho para cada dispositivo.

Editar 2

Divertido, mas tentei usar 6 anos depois e não consigo obter um bom resultado nos dispositivos Lollipop.

Provavelmente, a solução atual é usar 9 patches. O Android deveria ter criado uma solução fácil para esse problema depois de todo esse tempo.

Htafoya
fonte
Isso também funcionou para mim, mas não sei exatamente por que tive que usar -2dp em vez de -1dp. Se eu usasse o último, ainda poderia ver uma linha fina.
Edu Zamora
1
@EduZamora sim, parece que para dispositivos de alta densidade -1dp não funciona como esperado
htafoya
Também estou obtendo borda para todos os lados, mas não apenas borda inferior.
Cheok Yan Cheng
@YanChengCHEOK tente com 1px em vez de 1dp.
htafoya
@htafoya, essa é uma solução brilhante. Obrigado!
abriggs
52

Sei que esta pergunta foi postada há muito tempo, então a resposta não será usada pela pessoa que postou esta pergunta, mas ainda pode ajudar outras pessoas.

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

Use a insettag e dê um valor negativo para a borda lateral que você deseja remover.

Os valores possíveis são:

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

Nirmal Dhara
fonte
Sim, e não faça o que eu fiz e tente colocar o atributo de inserção na tag de traço sem ler o resto da resposta! (obrigado pela resposta BTW OP. Solução perfeita)
Kiran
elegante ! Eu amo esta solução
Hao Qi
41

Resolvi isso usando uma camada de lista, combinando duas formas, uma das quais com altura de 1 dp colocada na parte inferior

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>

Então, no arquivo 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"/>

O que preenche a lacuna entre table_options e exit_bar com um fundo e pouco antes de exit_bar imprimir uma linha de 1dp. Isso funcionou para mim, espero que ajude outra pessoa.

Resposta editada para colocar as camadas na ordem correta. Thx Alex!

Maragues
fonte
Pode ser útil não postar uma resposta se você realmente quiser recebê-la. Quando outros desenvolvedores veem que já existe uma resposta (embora neste caso seja realmente não), eles não estão tão inclinados a responder.
MrSnowflake
31

Outra abordagem das outras respostas usando preenchimento. Este pequeno recorte faz uma borda na parte superior e inferior.

<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_
fonte
4
Esta é de longe a melhor resposta se você precisar de cantos arredondados.
MacKinley Smith
Este também me ajudou tremendamente. Experimente e vote positivamente
Garoto
@ug_ Acho que essa é a melhor abordagem. Funciona perfeitamente, obrigado
Lalit Sharma
Trabalho. Parece completamente errado no painel de visualização do Android Studio (v1.1), mas no dispositivo está bom.
Murat Ögat
26

A resposta de @Maragues é invertida, pois os drawables da lista de camadas são desenhados de cima para baixo (o que significa que o último item da lista é desenhado no topo):

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

Isso preencherá efetivamente a forma com a cor da linha e, em seguida, desenhará a cor de fundo sobre ela, deixando o último 1dp livre para que a cor da linha apareça.

Alex Pretzlav
fonte
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>

ensolarado
fonte
2

Eu usei o seguinte código.

<?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.
fonte