Adicione margem acima do item principal do ListView (e abaixo do último) no Android

147

Essa é uma pergunta muito boa sobre o layout dos itens em um ListView no Android.

Eu tenho uma atividade com uma barra de título na parte superior e um ListView ocupando o resto da tela. Quero que meu ListView apareça com preenchimento de 10dp à esquerda, direita e superior, mas quando você rolar o ListView para cima, quero que cubra o preenchimento de 10dp superior antes de desaparecer sob a borda desbotada. Da mesma forma, quando você rola para a parte inferior, o último item da lista deve aparecer com 10dp entre a parte inferior do último item da lista e a parte inferior real da tela (se você está se perguntando por que, é porque há uma bonita imagem de fundo que eu quero mostrando o ListView).

Tentei adicionar preenchimento ao próprio ListView, mas quando você rola a lista, ele desaparece sob a borda do preenchimento.

Eu sou do fundo de desenvolvimento da Web e a analogia seria adicionar margem acima do primeiro item da lista (e abaixo do último item da lista).

Mick Byrne
fonte
especifique apenas as margens esquerda e direita ... tente colar seu xml aqui, para que eu possa ver o problema editar: espere, você quer dizer .... Você quer que o preenchimento superior e inferior também seja rolado?
Tek Yin
Não consigo especificar as margens esquerda e direita - não há 'margem' no layout do Android, apenas preenchimento. Mas, sim, eu quero que o preenchimento superior e inferior seja rolado - essa é uma boa maneira de descrevê-lo.
Mick Byrne
Eu já tentei vários métodos e ainda falhei .. Tenho alguns truques para fazer, mas será mais difícil fazer isso ... você coloca 2 objetos personalizados no item de lista na primeira e na última posição .. e usa o adaptador personalizado para detectar o item e desenhá-lo de forma diferente (altura estreita e transparente)
Tek Yin
Sim ... é nisso que tenho pensado em voltar também. Mas há todo tipo de complicações com isso, pois precisarei definir a cor do plano de fundo nos itens da lista, não na exibição, o que significa que precisarei hackear manualmente algum efeito para mostrar quando você tocar nas coisas . Obrigado pela ajuda de qualquer maneira ...
Mick Byrne
Boas notícias .. Eu tenho a solução ... você pode usar addHeaderView (View v) no ListActivity .. basta ligar getListView(). addHeaderView(capView)e getListView(). addHeaderView(botView) certificar-se de que chamou antes de inicializar o conteúdo da lista, por exemplo. setListAdapter (adaptador);
Tek Yin

Respostas:

397

Você escreveu:

Tentei adicionar preenchimento ao próprio ListView, mas quando você rola a lista, ele desaparece sob a borda do preenchimento.

Defina o ListView's clipToPaddingatributo como false. Isso habilitará o preenchimento ao redor do ListView e a rolagem até o final do layout (e não apenas até a borda do preenchimento).

Um exemplo:

<ListView
    android:id="@+id/list_view"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:divider="@android:color/transparent"
    android:dividerHeight="10.0sp"
    android:padding="16dip"
    android:clipToPadding="false"/>

android:clipToPaddingé um atributo XML de ViewGroup, a classe base para layouts e visualizações de contêineres.

A chamada de método relacionada é:

public void setClipToPadding (boolean clipToPadding)
Gunnar Karlsson
fonte
4
Além disso, este pode ser feita em um estilo ou tema via<item name="android:clipToPadding">false</item>
pjco
2
Oh, isso se aplica a ScrollView bem
pjco
4
Um pouco tarde para a discussão, mas observe que em dispositivos mais antigos (vi em alguns dispositivos 2.3.x), as visualizações de itens de lista são recicladas muito cedo. Enquanto a fase de desenho sabe que pode desenhar lá, a fase de layout não, por isso acha que o item já está fora da tela. Consulte stackoverflow.com/questions/15915226/… .
Jeffrey Klardie
@JeffreyKlardie Encontro o problema em que os itens são reciclados muito cedo em dispositivos mais antigos e até faz com que a barra de rolagem se redimensione rapidamente, o que parece realmente estranho. @pjco Não sei por que, mas definir clipToPaddingum estilo não funciona para mim, é como se não fosse aplicado. Embora, se eu configurá-lo diretamente no ListView, ele funciona.
ForceMagic
5
Não se esqueça android:scrollbarStyle="outsideOverlay"de modo a barra de rolagem vai todo o caminho através do preenchimento bem
jfcartier
19
View padding = new View(this);
padding.setHeight(20); // Can only specify in pixels unfortunately. No DIP :-(

ListView myListView = (ListView) findViewById(R.id.my_list_view);

myListView.addHeaderView(padding);
myListView.addFooterView(padding);

myListView.setAdapter(myAdapter);

O ListView acima terá um preenchimento de cabeçalho e rodapé de 20 pixels.

Jake Wilson
fonte
4
Obrigado pela resposta! Funciona bem!! Se você quiser colocar altura em dp isso pode ser feito usando DisplayMetrics: float mDensity = getResources().getDisplayMetrics().density; int height = (int) (50 * mDensity + 0.5f); padding.setHeight(height);
Tony Ceralva
3
Ou melhor, obtenha dimens no dp no nível Java usando getResources (). GetDimensionPixelOffset (R.dimen.some_value);
Greg7gkb
1
Verdadeiramente espantado com a quantidade Android coisas que eu aprender sobre StackOverflow contra aqueles que aprender no site desenvolvedores
TrueCoke
1
Ou melhor ainda(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, getResources().getDisplayMetrics());
Eugen Pechanec
1
Não há método "setHeight ()" para View na API 23. Em vez disso, podemos usar "setMinimumHeight ()".
KWA 14/07
10

Apêndice à resposta de @ Jakobud ...

Meu listView já estava usando as android:divider/android:dividerHeightpropriedades para criar espaços transparentes entre os itens listView. Isso me permitiu simplesmente adicionar os android:headerDividersEnablede android:footerDividersEnabledpropriedades e definir os pontos de vista de cabeçalho e rodapé para new View(Activity.this).

Pequena simplificação para casos em que você já possui divisores configurados no listView.

greg7gkb
fonte
1
Aconselho qualquer pessoa, sempre que possível, a usar divisórias em vez de nas margens e preenchimentos dos itens. Resposta
dzsonni
2

Minha solução usando a ListFragment, com base nas soluções de @Jakobud e @ greg7gkb.

ListView listView = getListView();
listView.setDivider(null);
listView.setDividerHeight(getResources().getDimensionPixelSize(R.dimen.divider_height));
listView.setHeaderDividersEnabled(true);
listView.setFooterDividersEnabled(true);
View padding = new View(getActivity());
listView.addHeaderView(padding);
listView.addFooterView(padding);
hleinone
fonte
1

A resposta de @Gunnar Karlsson é boa, mas há um problema de as visualizações de células serem recicladas prematuramente quando completamente atrás do preenchimento, mas ainda não totalmente fora da tela. A definição de clipToPadding = false é responsável por isso e pode ou não ser corrigida em uma versão futura do Android. ( Ao usar o clipToPadding no ListView, os itens são reciclados prematuramente )

Eu tenho uma boa solução simples, sem efeitos colaterais:

  1. Adicione um layout externo (linear ou relativo) ao seu cell_design.xml
  2. Nesse layout externo, adicione preenchimento (ou seja, 10dip) para criar uma "margem" em torno de toda a célula. (NB apenas preenchimento funcionará, não margem no layout externo)
  3. No conjunto ListView android:dividerHeight="-10dip", o oposto do que está ao redor da célula

Comparado com a outra resposta, não há necessidade de definir a cor do divisor. O preenchimento nas células superior e inferior estará presente, e o divisor negativo evitará divisores de altura dupla no meio.

James
fonte
"sem efeitos colaterais" isso não é inteiramente verdade. Adicionar outra camada em sua hierarquia de exibição, especialmente em um item de exibição de lista, significa degradar os desempenhos.
Teovald #