Non riesco a pubblicare un commento perché sono un nuovo utente, ma puoi descrivere COSA stai cercando di fare, al contrario di COME stai provando a farlo? Spesso, scoprirai che si tratta di una questione di design piuttosto che di codice. Soprattutto se provieni da una piattaforma diversa (ad esempio, iOS). Dall'esperienza, ho scoperto che la misurazione e i layout manuali in Android sono per lo più inutili se si progetta il layout correttamente in base alle esigenze aziendali.
MODIFICA: Come ho già detto, questo può essere risolto utilizzando alcune decisioni di progettazione. Userò il tuo esempio Nodi/Elenco (sperando che questo sia il tuo caso d'uso reale, ma la soluzione può essere estesa per un problema più generale).
Quindi, se ci pensiamo bene la vostra intestazione come un commento in un forum, e la lista di risposte al tuo commento, possiamo fare la seguente ipotesi:
Una lista è abbastanza, non due. Ogni elemento nell'elenco può essere un'intestazione (commento) o una voce di elenco (risposta). Ogni risposta è un commento, ma non tutti i commenti sono risposte.
Per l'articolo n, so se si tratta di un commento o una risposta (vale a dire un'intestazione o un elemento nell'elenco).
- Per l'articolo n, ho un membro booleano isVisible (default false; View.GONE).
Ora, è possibile utilizzare i seguenti componenti:
- un adattatore estesa classe
- Due XMLs layout: uno per il tuo commento, uno per la risposta. Puoi avere commenti illimitati e ogni commento può avere risposte illimitate. Entrambi soddisfano le tue esigenze.
- La classe del contenitore di frammenti o attività che implementa OnItemClickListener per mostrare/nascondere l'elenco.
Quindi vediamo un po 'di codice, vero?
primo luogo, il file XML:
fila Commento (l'intestazione)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/overall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
<TextView
android:id="@+id/comment_row_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
Ora la risposta di fila (un elemento nella lista)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/overall"
android:layout_width="match_parent"
android:layout_height="wrap_content"> <!-- this is important -->
<TextView
android:id="@+id/reply_row_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/> <!-- important -->
</RelativeLayout>
Ok, ora la scheda classe
public class CommentsListAdapter extends BaseAdapter implements OnClickListener
{
public static String TAG = "CommentsListAdapter";
private final int NORMAL_COMMENT_TYPE = 0;
private final int REPLY_COMMENT_TYPE = 1;
private Context context = null;
private List<Comment> commentEntries = null;
private LayoutInflater inflater = null;
//All replies are comments, but not all comments are replies. The commentsList includes all your data. (Remember that the refresh method allows you to add items to the list at runtime.
public CommentsListAdapter(Context context, List<Comment> commentsList)
{
super();
this.context = context;
this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.commentEntries = commentsList;
}
//For our first XML layout file
public static class CommentViewHolder
{
public RelativeLayout overall;
public TextView label;
}
//For our second XML
public static class ReplyViewHolder
{
public RelativeView replyOverall;
public TextView replyLabel;
}
@Override
public int getViewTypeCount()
{
return 2; //Important. We have two views, Comment and reply.
}
//Change the following method to determine if the current item is a header or a list item.
@Override
public int getItemViewType(int position)
{
int type = -1;
if(commentEntries.get(position).getParentKey() == null)
type = NORMAL_COMMENT_TYPE;
else if(commentEntries.get(position).getParentKey() == 0L)
type = NORMAL_COMMENT_TYPE;
else
type = REPLY_COMMENT_TYPE;
return type;
}
@Override
public int getCount()
{
return this.commentEntries.size(); //all data
}
@Override
public Object getItem(int position)
{
return this.commentEntries.get(position);
}
@Override
public long getItemId(int position)
{
return this.commentEntries.indexOf(this.commentEntries.get(position));
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
CommentViewHolder holder = null;
ReplyViewHolder replyHolder = null;
int type = getItemViewType(position);
if(convertView == null)
{
if(type == NORMAL_COMMENT_TYPE)
{
convertView = inflater.inflate(R.layout.row_comment_entry, null);
holder = new CommentViewHolder();
holder.label =(TextView)convertView.findViewById(R.id.comment_row_label);
convertView.setTag(holder);
}
else if(type == REPLY_COMMENT_TYPE)
{
convertView = inflater.inflate(R.layout.row_comment_reply_entry, null);
replyHolder = new ReplyViewHolder();
replyHolder.replyLable = (TextView)convertView.findViewById(R.id.reply_row_label);
convertView.setTag(replyHolder);
}
}
else
{
if(type == NORMAL_COMMENT_TYPE)
{
holder = (CommentViewHolder)convertView.getTag();
}
else if(type == REPLY_COMMENT_TYPE)
{
replyHolder = (ReplyViewHolder)convertView.getTag();
}
}
//Now, set the values of your labels
if(type == NORMAL_COMMENT_TYPE)
{
holder.label.setTag((Integer)position); //Important for onClick handling
//your data model object
Comment entry = (Comment)getItem(position);
holder.label.setText(entry.getLabel());
}
else if(type == REPLY_COMMENT_TYPE)
{
replyHolder = (ReplyViewHolder)convertView.getTag(); //if you want to implement onClick for list items.
//Or another data model if you decide to use multiple Lists
Comment entry = (Comment)getItem(position);
replyHolder.replyLabel.setText(entry.getLabel()));
//This is the key
if(entry.getVisible() == true)
replyHolder.replyLabel.setVisibility(View.VISIBLE);
else
replyHolder.replyLabel.setVisibility(View.GONE);
}
return convertView;
}
//You can use this method to add items to your list. Remember that if you are using two data models, then you will have to send the correct model list here and create another refresh method for the other list.
public void refresh(List<Comment> commentsList)
{
try
{
this.commentEntries = commentsList;
notifyDataSetChanged();
}
catch(Exception e)
{
e.printStackTrace();
Log.d(TAG, "::Error refreshing comments list.");
}
}
//Utility method to show/hide your list items
public void changeVisibility(int position)
{
if(this.commentEntries == null || this.commentEntries.size() == 0)
return;
Comment parent = (Comment)getItem(position);
for(Comment entry : this.commentEntries)
{
if(entry.getParent().isEqual(parent))
entry.setVisible(!entry.getVisible()); //if it's shown, hide it. Show it otherwise.
}
notifyDataSetChanged(); //redraw
}
}
Ok bene, ora abbiamo una lista di intestazioni con bambini nascosti (ricorda, abbiamo impostato la visibilità predefinita dei bambini su "andato"). Non è quello che volevamo, quindi sistemiamolo.
vostro contenitore di classe (frammento o attività) si avrà la seguente definizione XML
<!-- the @null divider means transparent -->
<ListView
android:id="@+id/comments_entries_list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:divider="@null"
android:dividerHeight="5dp" />
E il tuo onCreateView attuerà OnItemClickListener e hanno i seguenti
private ListView commentsListView = null;
private List<Comment>comments = null;
private static CommentsListAdapter adapter = null;
....
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
...
//comments list can be null here, and you can use adapter.refresh(data) to set the data
adapter = new CommentsListAdapter(getActivity(), comments);
this.commentsListView.setAdapter(adapter);
this.commentsListView.setOnClickListener(this); //to show your list
}
Ora per visualizzare l'elenco quando si fare clic su un'intestazione
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id)
{
adapter.changeVisibility(position);
}
Ora, se un elemento è c leccato e quell'elemento ha un genitore (ad es. voce dell'elenco), verrà mostrato/nascosto in base al suo stato corrente.
Alcuni commenti sul codice:
Ho scritto questo WordPad come io non ho un ambiente dev a portata di mano. Ci scusiamo per eventuali errori di compilazione.
Questo codice può essere ottimizzato: se si dispone di un set di dati molto grande, questo codice sarebbe lento poiché si sta ridisegnando l'intero elenco su ogni chiamata a changeVisibility(). È possibile mantenere due elenchi (uno per le intestazioni, uno per gli elementi dell'elenco) e in ChangeVisibility è possibile eseguire query solo sugli elementi dell'elenco).
Ho rinforzato l'idea che alcune decisioni di progettazione avrebbero reso la vita molto più facile. Ad esempio, se gli elementi dell'elenco erano in realtà solo un elenco di etichette, è possibile avere un file XML personalizzato (per l'intestazione) e una vista ListView al suo interno che è possibile impostare su View.GONE. Ciò farà sì che tutte le altre visualizzazioni facciano finta di non essere nemmeno lì e che il tuo layout funzionerà correttamente.
Spero che questo aiuti.
Non ho idea di come ci si avvicinerebbe a questo. Personalmente, vorrei lavorare su 'RecyclerView'. Lì, il lavoro di stendere i bambini è gestito da una classe manageriale dedicata e collegabile. È disponibile un'API più chiara e sono già disponibili gestori di terze parti che è possibile utilizzare (insieme ai tre in "recyclerview-v7") per vedere come affrontare il problema. – CommonsWare