Estou procurando um equivalente ao addHeaderView para uma exibição de reciclador. Basicamente, quero que uma imagem com 2 botões seja adicionada como cabeçalho à lista. Existe uma maneira diferente de adicionar uma exibição de cabeçalho a uma exibição de reciclador? Um exemplo de orientação seria útil
EDIT 2 (layouts de fragmentos adicionados):
Depois de adicionar instruções de log, parece que o getViewType apenas recebe uma posição 0. Isso leva o onCreateView a carregar apenas o layout a seguir:
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemViewType position: 0
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemViewType position: 0
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemViewType position: 0
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> onCreateViewHolder, viewtype: 0
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> onBindViewHolder, viewType: 0
A transição do fragmento para carregar o CommentFragment:
@Override
public void onPhotoFeedItemClick(View view, int position) {
if (fragmentManager == null)
fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (view.getId() == R.id.button_comment){
CommentFragment commentFragment = CommentFragment.newInstance("","", position);
fragmentTransaction.add(R.id.main_activity, commentFragment,"comment_fragment_tag");
fragmentTransaction.addToBackStack(Constants.TAG_COMMENTS);
fragmentTransaction.commit();
}
}
O onCreateView do fragmento:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_comment, container, false);
mRecyclerView = (RecyclerView) view.findViewById(R.id.list_recylclerview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(_context));
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mAdapter = new CommentAdapter(R.layout.row_list_comments, R.layout.row_header_comments, _context, comments);
mRecyclerView.setAdapter(mAdapter);
return view;
}
O fragmento que contém a revisão de reciclagem:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context="co.testapp.fragments.CommentFragment"
android:background="@color/white">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/list_recylclerview"
android:layout_width="match_parent"
android:layout_height="200dp" />
</RelativeLayout>
</RelativeLayout>
O layout da linha de comentários:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_margin="10dp"
android:background="@color/white">
<!--Profile Picture-->
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:id="@+id/profile_picture"
android:background="@color/blue_testapp"/>
<!--Name-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="First Name Last Name"
android:textSize="16dp"
android:textColor="@color/blue_testapp"
android:id="@+id/name_of_poster"
android:layout_toRightOf="@id/profile_picture"
/>
<!--Comment-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_marginTop="-5dp"
android:text="This is a test comment"
android:textSize="14dp"
android:textColor="@color/black"
android:id="@+id/comment"
android:layout_below="@id/name_of_poster"
android:layout_toRightOf="@id/profile_picture"/>
</RelativeLayout>
O cabeçalho
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="300dp"
android:id="@+id/header_photo"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
O código do adaptador (obrigado a hister por me ajudar a começar):
public class CommentAdapter extends RecyclerView.Adapter<ViewHolder>{
private final int rowCardLayout;
public static Context mContext;
private final int headerLayout;
private final String [] comments;
private static final int HEADER = 0;
private static final int OTHER = 0;
public CommentAdapter(int rowCardLayout, int headerLayout, Context context, String [] comments) {
this.rowCardLayout = rowCardLayout;
this.mContext = context;
this.comments = comments;
this.headerLayout = headerLayout;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
logger.i("onCreateViewHolder, viewtype: " + i); //viewtype always returns 0 so OTHER layout is never inflated
if (i == HEADER) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(headerLayout, viewGroup, false);
return new ViewHolderHeader(v);
}
else if (i == OTHER){
View v = LayoutInflater.from(viewGroup.getContext()).inflate(rowCardLayout, viewGroup, false);
return new ViewHolderComments(v);
}
else
throw new RuntimeException("Could not inflate layout");
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
logger.i("onBindViewHolder, viewType: " + i);
if (viewHolder instanceof ViewHolderComments)
((ViewHolderComments) viewHolder).comment.setText(comments[i].toString());
if (viewHolder instanceof ViewHolderHeader)
((ViewHolderHeader) viewHolder).header.setImageResource(R.drawable.image2);
else {
logger.e("no instance of viewholder found");
}
}
@Override
public int getItemCount() {
int count = comments.length + 1;
logger.i("getItemCount: " + count);
return count;
}
@Override
public int getItemViewType(int position) {
logger.i("getItemViewType position: " + position);
if (position == HEADER)
return HEADER;
else
return OTHER;
}
public static class ViewHolderComments extends RecyclerView.ViewHolder {
public TextView comment;
public ImageView image;
public ViewHolderComments(View itemView) {
super(itemView);
comment = (TextView) itemView.findViewById(R.id.comment);
image = (ImageView) itemView.findViewById(R.id.image);
}
}
public static class ViewHolderHeader extends RecyclerView.ViewHolder {
public final ImageView header;
public ViewHolderHeader(View itemView){
super(itemView);
header = (ImageView) itemView.findViewById(R.id.header_photo);
}
}
}
Usando o código acima, apenas o layout do cabeçalho é exibido como viewType é sempre 0. Parece com isso . Se eu forçar o outro esquema parece que esta :
fonte
Respostas:
Não existe uma maneira fácil,
listview.addHeaderView()
mas você pode conseguir isso adicionando um tipo ao seu adaptador para cabeçalho.Aqui está um exemplo
link para gist -> aqui
fonte
private String getItem(int position) { return data[position + 1]; }
Causa um NPE. Como nossa posição foi aumentada em um, devido ao cabeçalho, precisamos subtrair 1 para obter o item correto de nossos dados [].private String getItem(int position) { return data[position - 1]; }
setSpanSizeLookup
paraGridLayoutManager
, assim que seu cabeçalho irá tomar todas as colunasFácil e reutilizável
ItemDecoration
Cabeçalhos estáticos podem ser facilmente adicionados com
ItemDecoration
e sem alterações adicionais.A decoração também é reutilizável, pois não há necessidade de modificar o adaptador ou o
RecyclerView
mesmo.O código de exemplo fornecido abaixo exigirá uma visualização para adicionar ao topo, que pode ser inflada como todo o resto. Pode ficar assim:
Por que estático ?
Se você apenas precisar exibir texto e imagens, esta solução é para você - não há possibilidade de interação do usuário, como botões ou exibir pagers, pois ela será desenhada apenas no topo da sua lista.
Tratamento de lista vazia
Se não houver vista para decorar, a decoração não será desenhada. Você ainda terá que lidar com uma lista vazia. (Uma solução possível seria adicionar um item fictício ao adaptador.)
O código
Você pode encontrar o código fonte completo aqui no GitHub, incluindo um
Builder
para ajudar na inicialização do decorador ou apenas usar o código abaixo e fornecer seus próprios valores ao construtor.Certifique-se de definir um correto
layout_height
para sua visualização. por exemplo,match_parent
pode não funcionar corretamente.Observe: O projeto GitHub é meu playground pessoal. Não é thorougly testada, razão pela qual não há nenhuma biblioteca ainda .
O que isso faz?
Um
ItemDecoration
é um desenho adicional para um item de uma lista. Nesse caso, uma decoração é desenhada na parte superior do primeiro item.A vista é medida e organizada e, em seguida, é desenhada para o topo do primeiro item. Se um efeito de paralaxe for adicionado, ele também será cortado nos limites corretos.
fonte
Sinta-se livre para usar minha biblioteca, disponível aqui .
Vamos criar um cabeçalho
View
para qualquer umRecyclerView
que useLinearLayoutManager
ouGridLayoutManager
com apenas uma chamada de método simples.fonte
Vai mostrar para você criar cabeçalho com itens em uma exibição Reciclador.
Etapa 1 - Adicione dependência ao seu arquivo gradle.
O Cardview é usado para fins de decoração.
Passo 2 - Faça três arquivos xml. Um para a atividade principal; o segundo para o layout do cabeçalho; o terceiro para o layout do item de lista.
activity_main.xml
header.xml
list.xml
Etapa 3- Crie três classes de bean.
Header.java
ContentItem.java
ListItem.java
Etapa 4- Crie um adaptador chamado MyRecyclerAdapter.java
Etapa 5- No MainActivity, adicione o seguinte código:
A função getList () está gerando dinamicamente os dados para os cabeçalhos e itens da lista.
fonte
Você pode consegui-lo usando a biblioteca SectionedRecyclerViewAdapter , que possui o conceito de "Seções", em que seção possui um cabeçalho, rodapé e conteúdo (lista de itens). No seu caso, você pode precisar apenas de uma seção, mas pode ter muitas:
1) Crie uma classe de seção personalizada:
2) Crie um ViewHolder personalizado para os itens:
3) Configure o ReclyclerView com o SectionedRecyclerViewAdapter
fonte
Você pode apenas colocar seu cabeçalho e seu RecyclerView em um NestedScrollView:
Para que a rolagem funcione corretamente, você precisa desativar a rolagem aninhada no seu RecyclerView:
fonte
A API nativa não possui esse recurso "addHeader", mas possui o conceito de "addItem".
Consegui incluir esse recurso específico de cabeçalhos e se estende para rodapés também no meu projeto FlexibleAdapter . Eu chamei de Cabeçalhos e Rodapés Roláveis .
Aqui como eles funcionam:
Cabeçalhos e rodapés roláveis são itens especiais que rolam junto com todos os outros, mas não pertencem aos itens principais (itens de negócios) e são sempre manipulados pelo adaptador ao lado dos itens principais. Esses itens estão persistentemente localizados na primeira e na última posição.
Há muito a dizer sobre eles, melhor ler a página detalhada da wiki .
Além disso, o FlexibleAdapter permite que você crie cabeçalhos / seções, além de poder colocá-los visíveis e dezenas de outros recursos, como itens expansíveis, rolagem sem fim, extensões de interface do usuário etc. ... tudo em uma biblioteca!
fonte
Com base nesta postagem , criei uma subclasse de RecyclerView.Adapter que suporta um número arbitrário de cabeçalhos e rodapés.
https://gist.github.com/mheras/0908873267def75dc746
Embora pareça ser uma solução, também acho que isso deve ser gerenciado pelo LayoutManager. Infelizmente, eu preciso dele agora e não tenho tempo para implementar um StaggeredGridLayoutManager do zero (nem mesmo estender a partir dele).
Ainda estou testando, mas você pode experimentá-lo, se quiser. Entre em contato se encontrar algum problema.
fonte
Há mais uma solução que abrange todos os casos de uso acima: CompoundAdapter: https://github.com/negusoft/CompoundAdapter-android
Você pode criar um AdapterGroup que mantenha seu adaptador como ele é, juntamente com um adaptador com um único item para representar o cabeçalho. O código é fácil e legível:
O AdapterGroup também permite o aninhamento, portanto, para um adaptador com seções, você pode criar um AdapterGroup por seção. Em seguida, coloque todas as seções em um AdapterGroup raiz.
fonte
O HeaderView depende do LayoutManager. Nenhum dos LayoutManagers padrão suporta isso e provavelmente não. O HeaderView no ListView cria muita complexidade sem nenhum benefício significativo.
Eu sugeriria a criação de uma classe de adaptador base que adiciona itens para cabeçalhos, se fornecidos. Não se esqueça de substituir os métodos de notificação * para compensá-los adequadamente, dependendo se o cabeçalho está presente ou não.
fonte
ListView.addHeaderView
a resposta a esta pergunta.Depois - Substitua o método getItemViewTpe *** Mais importante
método onCreateViewHolder
método onBindViewHolder
no acabamento implementa a classe estática ViewHolders
fonte
aqui alguns itens de decoração para reciclagem
fonte
Fiz uma implementação baseada na do @ hister para meus propósitos pessoais, mas usando herança.
Oculto os mecanismos de detalhes da implementação (como adicionar 1 a
itemCount
, subtrair 1 deposition
) em uma superclasse abstrataHeadingableRecycleAdapter
, implementando métodos necessários do Adapter comoonBindViewHolder
,getItemViewType
egetItemCount
, tornando esses métodos finais e fornecendo novos métodos com lógica oculta ao cliente:onAddViewHolder(RecyclerView.ViewHolder holder, int position)
,onCreateViewHolder(ViewGroup parent)
,itemCount()
Aqui estão a
HeadingableRecycleAdapter
classe e um cliente. Deixei o layout do cabeçalho um pouco codificado porque ele atende às minhas necessidades.fonte
Talvez agrupe o cabeçalho e recicle a visualização em um layout do coordenador :
fonte
Provavelmente http://alexzh.com/tutorials/multiple-row-layouts-using-recyclerview/ ajudará. Ele usa apenas RecyclerView e CardView. Aqui está um adaptador:
E aqui está uma entidade:
fonte
você pode criar addHeaderView e usar
adapter.addHeaderView(View)
.Esse código cria o
addHeaderView
para mais de um cabeçalho. os cabeçalhos devem ter:android:layout_height="wrap_content"
fonte
Já faz alguns anos, mas caso alguém esteja lendo isso mais tarde ...
O problema está na declaração constante:
Se você declarar os dois como zero, sempre terá zero!
fonte
Eu implementei a mesma abordagem proposta por EC84B4 resposta , mas abstraí o RecycleViewAdapter e o tornei facilmente recuperável por meio de interfaces.
Portanto, para usar minha abordagem, você deve adicionar as seguintes classes base e interfaces ao seu projeto:
1) Interface que fornece dados para o Adaptador (coleção do tipo genérico T e parâmetros adicionais (se necessário) do tipo genérico P)
2) Fábrica para encadernar seus itens (cabeçalho / item):
3) Fábrica para viewHolders (cabeçalho / itens):
4) Classe base para adaptador com cabeçalho:
Exemplo de uso :
1) Implementação do IRecycleViewListHolder:
2) Implementação IViewHolderBinderFactory:
3) Implementação IViewHolderFactory:
4) Adaptador de derivação
5) Instanciar classe de adaptador:
PS : AssetItemViewHolder, AssetBasedListItemBinding, etc. minha aplicação possui estruturas que devem ser trocadas por você, para seus próprios fins.
fonte