Esiste un modo standard per bloccare la voce di gruppo nella parte superiore dello schermo durante lo scorrimento degli elementi del gruppo. Ho visto esempi simili con ListView. Quali interfacce dovrei implementare o quali metodi sostituire?Gruppi aggiunti in ExpandableListView
risposta
ho trovato soluzione basata su Pinned Header ListView di Pietro Kuterna e ExpandableList1.java campione Android. PinnedHeaderExpListView.java
package com.example;
import com.example.ExpandableList.MyExpandableListAdapter;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.TextView;
/**
* A ListView that maintains a header pinned at the top of the list. The
* pinned header can be pushed up and dissolved as needed.
*/
public class PinnedHeaderExpListView extends ExpandableListView{
/**
* Adapter interface. The list adapter must implement this interface.
*/
public interface PinnedHeaderAdapter {
/**
* Pinned header state: don't show the header.
*/
public static final int PINNED_HEADER_GONE = 0;
/**
* Pinned header state: show the header at the top of the list.
*/
public static final int PINNED_HEADER_VISIBLE = 1;
/**
* Pinned header state: show the header. If the header extends beyond
* the bottom of the first shown element, push it up and clip.
*/
public static final int PINNED_HEADER_PUSHED_UP = 2;
/**
* Configures the pinned header view to match the first visible list item.
*
* @param header pinned header view.
* @param position position of the first visible list item.
* @param alpha fading of the header view, between 0 and 255.
*/
void configurePinnedHeader(View header, int position, int alpha);
}
private static final int MAX_ALPHA = 255;
private MyExpandableListAdapter mAdapter;
private View mHeaderView;
private boolean mHeaderViewVisible;
private int mHeaderViewWidth;
private int mHeaderViewHeight;
public PinnedHeaderExpListView(Context context) {
super(context);
}
public PinnedHeaderExpListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PinnedHeaderExpListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setPinnedHeaderView(View view) {
mHeaderView = view;
// Disable vertical fading when the pinned header is present
// TODO change ListView to allow separate measures for top and bottom fading edge;
// in this particular case we would like to disable the top, but not the bottom edge.
if (mHeaderView != null) {
setFadingEdgeLength(0);
}
requestLayout();
}
@Override
public void setAdapter(ExpandableListAdapter adapter) {
super.setAdapter(adapter);
mAdapter = (MyExpandableListAdapter)adapter;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mHeaderView != null) {
measureChild(mHeaderView, widthMeasureSpec, heightMeasureSpec);
mHeaderViewWidth = mHeaderView.getMeasuredWidth();
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mHeaderView != null) {
mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
configureHeaderView(getFirstVisiblePosition());
}
}
/**
* animating header pushing
* @param position
*/
public void configureHeaderView(int position) {
final int group = getPackedPositionGroup(getExpandableListPosition(position));
int groupView = getFlatListPosition(getPackedPositionForGroup(group));
if (mHeaderView == null) {
return;
}
mHeaderView.setOnClickListener(new OnClickListener() {
public void onClick(View header) {
if(!expandGroup(group)) collapseGroup(group);
}
});
int state,nextSectionPosition = getFlatListPosition(getPackedPositionForGroup(group+1));
if (mAdapter.getGroupCount()== 0) {
state = PinnedHeaderAdapter.PINNED_HEADER_GONE;
}else if (position < 0) {
state = PinnedHeaderAdapter.PINNED_HEADER_GONE;
}else if (nextSectionPosition != -1 && position == nextSectionPosition - 1) {
state=PinnedHeaderAdapter.PINNED_HEADER_PUSHED_UP;
}else state=PinnedHeaderAdapter.PINNED_HEADER_VISIBLE;
switch (state) {
case PinnedHeaderAdapter.PINNED_HEADER_GONE: {
mHeaderViewVisible = false;
break;
}
case PinnedHeaderAdapter.PINNED_HEADER_VISIBLE: {
mAdapter.configurePinnedHeader(mHeaderView, group, MAX_ALPHA);
if (mHeaderView.getTop() != 0) {
mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
}
mHeaderViewVisible = true;
break;
}
case PinnedHeaderAdapter.PINNED_HEADER_PUSHED_UP: {
View firstView = getChildAt(0);
if(firstView==null){
if (mHeaderView.getTop() != 0) {
mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
}
mHeaderViewVisible = true;
break;
}
int bottom = firstView.getBottom();
int itemHeight = firstView.getHeight();
int headerHeight = mHeaderView.getHeight();
int y;
int alpha;
if (bottom < headerHeight) {
y = (bottom - headerHeight);
alpha = MAX_ALPHA * (headerHeight + y)/headerHeight;
} else {
y = 0;
alpha = MAX_ALPHA;
}
mAdapter.configurePinnedHeader(mHeaderView, group, alpha);
//выползание
if (mHeaderView.getTop() != y) {
mHeaderView.layout(0, y, mHeaderViewWidth, mHeaderViewHeight + y);
}
mHeaderViewVisible = true;
break;
}
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mHeaderViewVisible) {
drawChild(canvas, mHeaderView, getDrawingTime());
}
}
}
ExpandableList.java
package com.example;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.LayoutParams;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListAdapter;
import android.widget.SectionIndexer;
import android.widget.TextView;
import android.widget.Toast;
import com.example.PinnedHeaderExpListView.PinnedHeaderAdapter;
/**
* Demonstrates expandable lists using a custom {@link ExpandableListAdapter}
* from {@link BaseExpandableListAdapter}.
*/
public class ExpandableList extends Activity {
MyExpandableListAdapter mAdapter;
PinnedHeaderExpListView elv;
private int mPinnedHeaderBackgroundColor;
private int mPinnedHeaderTextColor;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Set up our adapter
mAdapter = new MyExpandableListAdapter();
elv = (PinnedHeaderExpListView) findViewById(R.id.list);
elv.setAdapter(mAdapter);
mPinnedHeaderBackgroundColor = getResources().getColor(android.R.color.black);
mPinnedHeaderTextColor = getResources().getColor(android.R.color.white);
elv.setGroupIndicator(null);
View h = LayoutInflater.from(this).inflate(R.layout.header, (ViewGroup) findViewById(R.id.root), false);
elv.setPinnedHeaderView(h);
elv.setOnScrollListener((OnScrollListener) mAdapter);
elv.setDividerHeight(0);
}
/**
* A simple adapter which maintains an ArrayList of photo resource Ids.
* Each photo is displayed as an image. This adapter supports clearing the
* list of photos and adding a new photo.
*
*/
public class MyExpandableListAdapter extends BaseExpandableListAdapter implements PinnedHeaderAdapter, OnScrollListener{
// Sample data set. children[i] contains the children (String[]) for groups[i].
private String[] groups = { "People Names", "Dog Names", "Cat Names", "Fish Names" };
private String[][] children = {
{ "Arnold", "Barry", "Chuck", "David", "Stas", "Oleg", "Max","Alex","Romeo", "Adolf" },
{ "Ace", "Bandit", "Cha-Cha", "Deuce", "Nokki", "Baron", "Sharik", "Toshka","SObaka","Belka","Strelka","Zhuchka"},
{ "Fluffy", "Snuggles","Cate", "Yasha","Bars" },
{ "Goldy", "Bubbles","Fluffy", "Snuggles","Guffy", "Snoopy" }
};
public Object getChild(int groupPosition, int childPosition) {
return children[groupPosition][childPosition];
}
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
public int getChildrenCount(int groupPosition) {
return children[groupPosition].length;
}
public TextView getGenericView() {
// Layout parameters for the ExpandableListView
AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, 64);
TextView textView = new TextView(ExpandableList.this);
textView.setLayoutParams(lp);
// Center the text vertically
textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
// Set the text starting position
textView.setPadding(36, 0, 0, 0);
return textView;
}
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
TextView textView = getGenericView();
textView.setText(getChild(groupPosition, childPosition).toString());
return textView;
}
public Object getGroup(int groupPosition) {
return groups[groupPosition];
}
public int getGroupCount() {
return groups.length;
}
public long getGroupId(int groupPosition) {
return groupPosition;
}
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) {
TextView textView = (TextView) LayoutInflater.from(getApplicationContext()).inflate(R.layout.header, parent, false);
textView.setText(getGroup(groupPosition).toString());
return textView;
}
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
public boolean hasStableIds() {
return true;
}
/**
* размытие/пропадание хэдера
*/
public void configurePinnedHeader(View v, int position, int alpha) {
TextView header = (TextView) v;
final String title = (String) getGroup(position);
header.setText(title);
if (alpha == 255) {
header.setBackgroundColor(mPinnedHeaderBackgroundColor);
header.setTextColor(mPinnedHeaderTextColor);
} else {
header.setBackgroundColor(Color.argb(alpha,
Color.red(mPinnedHeaderBackgroundColor),
Color.green(mPinnedHeaderBackgroundColor),
Color.blue(mPinnedHeaderBackgroundColor)));
header.setTextColor(Color.argb(alpha,
Color.red(mPinnedHeaderTextColor),
Color.green(mPinnedHeaderTextColor),
Color.blue(mPinnedHeaderTextColor)));
}
}
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (view instanceof PinnedHeaderExpListView) {
((PinnedHeaderExpListView) view).configureHeaderView(firstVisibleItem);
}
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
}
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<view class="com.example.PinnedHeaderExpListView"
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
header.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="25dp"
android:background="@android:color/black" >
</TextView>
Esso funziona come previsto, tranne che cliccando su intestazione. Mi piacerebbe che facendo clic sull'intestazione fosse uguale facendo clic sull'elemento del gruppo, ma l'evento non si verifica e OnClickListener non ottiene il controllo. Perché ?
EDIT: clic sul colpo di testa funziona anche se si aggiunge seguente pezzo di codice all'interno onCreate()
metodo ExpandableList.java
attività.
elv.setOnGroupClickListener(new OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
return false;
}
});
in Adapter:
public void setSelectedPosition(int position){
this.listChildPosition=position;
}
in getchildview
if (listChildPosition == childPosition) {
convertView.setBackgroundColor(context.getResources().getColor(
R.color.white));
} else {
convertView.setBackgroundColor(context.getResources().getColor(
R.color.expandlist));
}
in onChildClick
adapter.setSelectedPosition(childPosition);
adapter.notifyDataSetChanged();
v.setSelected(true);
non è questo, quello che ho chiesto, a tutti –
Ho cercato di implementare la soluzione di Homo Incognito e incontrare lo stesso problema di intestazione appuntato non essere cliccabile.
Il colpevole sembra essere il ListView stesso che consuma tutto l'evento click quindi non passa nessuno alla nostra vista intestazione 'aumentata'. Quindi potresti provare a scavare nell'implementazione della gestione dei clic di ExpandableListView, il che è piuttosto un disastro considerando la sua ereditarietà fino ad AdapterView.
Invece di provare a bloccare il clic da ListView, provo a circumnavigare tale problema simulando il click dell'intestazione dall'elemento dell'elenco sottostante. Per fare ciò, è necessario implementare onChildClick
per vedere se la posizione dell'elemento su cui si fa clic si trova sotto l'intestazione bloccata, in tal caso, quindi è possibile inoltrare il clic all'intestazione vera, in caso contrario, quindi elaborare il clic per quello oggetto normalmente.
Nell'esempio che segue, quando l'elemento cliccato è sotto l'intestazione bloccato, ho semplicemente fatto il ListView scorrimento alla vera intestazione, sostituendo così il 'aumentata' intestazione bloccato con la vera intestazione, e l'utente può intraprendere ulteriori azioni da lì, ad es collassare il gruppo.
Si noti che tale flusso usabilità funziona solo se non si dispone di alcuna vista cliccabile sulle voci di intestazione, in caso contrario si dovrà fare tutto il relè click e la mappatura tra l'intestazione virtuale appuntato e il vero te stesso intestazione con onInterceptTouchEvent
.
seguente codice di Homo Incognito, nel PinnedHeaderExpListView.java
aggiungere il seguente metodo:
public int getHeaderViewHeight(){
return mHeaderViewHeight;
}
nell'attività onCreate
, aggiungere il seguente:
elv.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
// we need to obtain the relative y coordinate of the child view,
// not its clicked subview, thus first we try to calculate its true index
long packedPos = ExpandableListView.getPackedPositionForChild(groupPosition, childPosition);
int viewPos = elv.getFlatListPosition(packedPos) - elv.getFirstVisiblePosition();
View childView = parent.getChildAt(viewPos); // got it
if (childView.getTop() < elv.getHeaderViewHeight()*.75){
// if the clicked child item overlaps more than 25%
// of pinned header, consider it being underneath
long groupPackedPos = ExpandableListView.getPackedPositionForGroup(groupPosition);
int groupFlatPos = elv.getFlatListPosition(groupPackedPos);
elv.smoothScrollToPosition(groupFlatPos);
}
return true;
}
});
nella risposta di Homo Incognito, vista bambino la visualizzazione a testa fissa non può fare clic e ricevere l'evento click, ma ho trovato un modo. Ho messo il codice in: https://github.com/chenjishi/PinnedHeadListView
private final Rect mRect = new Rect();
private final int[] mLocation = new int[2];
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (mHeaderView == null) return super.dispatchTouchEvent(ev);
if (mHeaderViewVisible) {
final int x = (int) ev.getX();
final int y = (int) ev.getY();
mHeaderView.getLocationOnScreen(mLocation);
mRect.left = mLocation[0];
mRect.top = mLocation[1];
mRect.right = mLocation[0] + mHeaderView.getWidth();
mRect.bottom = mLocation[1] + mHeaderView.getHeight();
if (mRect.contains(x, y)) {
if (ev.getAction() == MotionEvent.ACTION_UP) {
performViewClick(x, y);
}
return true;
} else {
return super.dispatchTouchEvent(ev);
}
} else {
return super.dispatchTouchEvent(ev);
}
}
private void performViewClick(int x, int y) {
if (null == mHeaderView) return;
final ViewGroup container = (ViewGroup) mHeaderView;
for (int i = 0; i < container.getChildCount(); i++) {
View view = container.getChildAt(i);
/**
* transform coordinate to find the child view we clicked
* getGlobalVisibleRect used for android 2.x, getLocalVisibleRect
* user for 3.x or above, maybe it's a bug
*/
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
view.getGlobalVisibleRect(mRect);
} else {
view.getLocalVisibleRect(mRect);
int width = mRect.right - mRect.left;
mRect.left = Math.abs(mRect.left);
mRect.right = mRect.left + width;
}
if (mRect.contains(x, y)) {
view.performClick();
break;
}
}
}
questo è il mio modo di gestire l'evento click in vista appuntato, ignorare dispatchTouchEvent.
- 1. ExpandableListView - nascondi l'indicatore per i gruppi senza figli
- 2. come nascondere l'indicatore ExpandableListView per gruppi senza figli
- 3. ExpandableListView inside ExpandableListView
- 4. multistrato ExpandableListView
- 5. ExpandableListView multilivello in Android
- 6. definizione ExpandableListView in xml
- 7. Gruppi nidificati di Django: Gruppi in gruppi
- 8. mvvmcross expandablelistview
- 9. Casella di controllo in ExpandableListView
- 10. Regola dinamicamente l'altezza delle intestazioni di gruppo in un ExpandableListView
- 11. Aggiungi animazione a ExpandableListView
- 12. ExpandableListView e caselle di controllo
- 13. ExpandableListView e NavigationDrawer
- 14. Android ExpandableListView posizione di gruppo sempre 0
- 15. Android LongClickListener su elementi del gruppo ExpandableListView
- 16. Come implementare ExpandableListview multilivello in Android?
- 17. ChoiceMode è compatibile con ExpandableListView?
- 18. Android ExpandableListView Parent con pulsante
- 19. ExpandableListView Android divisore è invisibile
- 20. panda raggruppa in gruppi
- 21. Come gestire l'evento click secondario in Expandablelistview in Android?
- 22. Git - file scartare aggiunti
- 23. Come aggiungere ListView a tre livelli in ExpandableListView in Android
- 24. Come nascondere il gruppo in ExpandableListView in Android
- 25. Precaricamento gruppi
- 26. Suddivisione dei livelli dell'applicazione in diversi gruppi
- 27. inizializzazione pulsanti radio aggiunti dinamicamente in materializzare
- 28. gruppi di cattura in sed
- 29. gruppi CONCAT in SQL Server
- 30. Moduli, gruppi, intestazioni in CLR
Dove prendi le sezioni da? Perché il gruppo è l'elemento della lista con i bambini. Non vedo da nessuna parte dove si impostano le intestazioni e le sezioni. Potresti aggiungere screenshot in modo che possa sapere cosa aspettarti da questo codice? Come imposti le sezioni? In configurePinnedHeader, crea un'intestazione, ma viene richiamata solo una volta perché non so come creare le sezioni che vanno sotto le intestazioni. Ho letto la risposta molte volte e non riesco a capirlo. Aiuto per favore? –
Questo è molto bello ... grazie :) possiamo rendere le intestazioni di gruppo sempre visibili ... nella sua forma attuale solo l'intestazione attiva corrente è bloccata se il numero di elementi ad esso associati è grande e il altre intestazioni vengono espulse dall'area di visualizzazione – Nav
Hey @Homo esiste un modo per aggiungere l'animazione all'operazione di espansione/compressione? – Tony