zoukankan      html  css  js  c++  java
  • ExpandableListView的使用以及信息的高亮显示

    ExpandableListView是ListView控件的延伸,它能够对数据进行分组显示和隐藏,并统计总数量。可进行滚动,对某一内容高亮显示。


    <1>编写xml布局文件,用于获取ExpandableListView对象

    sf_activity_contact_list.xml

    <span style="font-family:Microsoft YaHei;"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/contacts_list_holder"
        style="@style/SF_ActivityBackground"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/sf_activity_background_color"
        android:overScrollMode="always"
        android:scrollbarStyle="outsideInset"
        android:scrollbars="vertical">
    
        <!-- style="@style/SF_ActivityBackground" -->
    
        <ExpandableListView
            android:id="@+id/contacts_list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:fastScrollEnabled="true" >
        </ExpandableListView>
    
    </LinearLayout></span>

    <2>编写Activity界面,获取ExpandableListView对象。并设置适配器和对应的属性、事件等等

    package com.snapfish.ui;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.json.JSONException;
    import org.json.JSONObject;
    
    import android.app.AlertDialog;
    import android.app.SearchManager;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.graphics.PixelFormat;
    import android.os.Bundle;
    import android.support.v4.view.MenuItemCompat;
    import android.support.v7.widget.SearchView;
    import android.support.v7.widget.SearchView.OnQueryTextListener;
    import android.text.TextUtils;
    import android.view.LayoutInflater;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.view.WindowManager;
    import android.view.WindowManager.LayoutParams;
    import android.widget.AbsListView;
    import android.widget.AbsListView.OnScrollListener;
    import android.widget.EditText;
    import android.widget.ExpandableListView;
    import android.widget.ExpandableListView.OnChildClickListener;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import com.snapfish.R;
    import com.snapfish.android.generated.bean.AddressType;
    import com.snapfish.android.generated.bean.Entry;
    import com.snapfish.android.generated.bean.MrchShippingOption;
    import com.snapfish.android.generated.bean.OpenSocialResponseType;
    import com.snapfish.android.generated.bean.Person;
    import com.snapfish.android.generated.bean.PublisherOrder;
    import com.snapfish.android.generated.bean.PublisherOrderAddress;
    import com.snapfish.checkout.IUserData;
    import com.snapfish.internal.core.SFConstants;
    import com.snapfish.internal.database.SFContactsHolderDB;
    import com.snapfish.internal.datamodel.SFContact;
    import com.snapfish.internal.datamodel.SFContactDBManager;
    import com.snapfish.internal.event.SFEventManager;
    import com.snapfish.internal.event.SFIEventListener;
    import com.snapfish.internal.event.SFLocaleContactsEvent;
    import com.snapfish.internal.event.SFRemoteContactsEvent;
    import com.snapfish.util.CShippingOptionsAdapter;
    import com.snapfish.util.SFActivityUtils;
    import com.snapfish.util.SFContactExpandableListAdapter;
    import com.snapfish.util.SFLogger;
    
    public class SFContactsListActivity extends ABaseActivity { // implements
    															// LoaderManager.LoaderCallbacks<Cursor>
    
    	private static final SFLogger sLogger = SFLogger
    			.getInstance(SFContactsListActivity.class.getName());
    
    	private Context m_ctx;
    
    	private TextView m_contactNameOverlay;
    	private boolean m_visible;
    
    	// private static final int CONTACT_DATA_LOADER = 111;
    
    	OnScrollListener mItemsListScrollListener = new OnScrollListener() {
    
    		@Override
    		public void onScrollStateChanged(AbsListView view, int scrollState) {
    			m_visible = true;
    
    			// when stop scrolling
    			if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
    				m_contactNameOverlay.setVisibility(View.INVISIBLE);
    				m_visible = false;
    			}
    			// when scrolling and the finger is on the screen
    			else if (scrollState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
    
    			}
    			// when scrolling and the finger perform an action above
    			else if (scrollState == OnScrollListener.SCROLL_STATE_FLING) {
    
    			}
    		}
    
    		@Override
    		public void onScroll(AbsListView view, int firstVisibleItem,
    				int visibleItemCount, int totalItemCount) {
    			if (visibleItemCount > 0 && m_visible) {
    				SFContact contact = mPhoneContacts.get(firstVisibleItem);
    				m_contactNameOverlay.setText(String.valueOf(contact.getName()
    						.charAt(0)));
    				m_contactNameOverlay.setVisibility(View.VISIBLE);
    			}
    		}
    	};
    
    	/**************************************************
    	 * The event of getting locale contacts
    	 *************************************************/
    	private SFIEventListener<SFLocaleContactsEvent> m_localeContactListEvent = new SFIEventListener<SFLocaleContactsEvent>() {
    
    		@Override
    		public void onEvent(SFLocaleContactsEvent event) {
    			// TODO The event of getting locale contacts
    			sLogger.debug("****************The event of getting locale contacts*****************");
    			hideProgressDialog();
    			if (null != event && event.getContactsList() != null) {
    				mPhoneContacts = event.getContactsList();
    
    				showProgressDialog(getString(R.string.sf_please_wait),
    						getString(R.string.sf_progress_remote_contact_list));
    				// Get all remote contacts
    				SFContactDBManager.asyncGetAllRemoteContacts(getSession());
    			}
    		}
    	};
    
    	/**************************************************
    	 * The event of getting remote contacts
    	 *************************************************/
    	private SFIEventListener<SFRemoteContactsEvent> m_remoteContactListEvent = new SFIEventListener<SFRemoteContactsEvent>() {
    
    		@Override
    		public void onEvent(SFRemoteContactsEvent event) {
    			// TODO The event of getting remote contacts
    			sLogger.debug("****************The event of getting remote contacts*****************");
    			hideProgressDialog();
    			if (null != event && event.getOpenSocialResponseType() != null) {
    				OpenSocialResponseType osrt = event.getOpenSocialResponseType();
    				if (null != osrt) {
    					List<Entry> entries = osrt.getEntryList();
    					if (null != entries && !entries.isEmpty()) {
    						int entrySize = entries.size();
    						for (int i = 0; i < entrySize; i++) {
    							try {
    								Person person = Person.newFromJSON(entries.get(
    										i).toJSON());
    								if (null != person) {
    									AddressType address = person.getAddress();
    									String displayName = person
    											.getDisplayName();
    									if (isValidContact(address)
    											&& !TextUtils.isEmpty(displayName)) {
    										SFContact contact = new SFContact(
    												IUserData.EUserDataType.SNAPFISH,
    												person.getId(),
    												displayName,
    												address.getStreet1(),
    												address.getCity(),
    												address.getProvince(),
    												address.getPostalCode(),
    												SFContact.ContactAddressType.TYPE_OTHER);
    
    										contact.setGuessedPrecision(SFContact.GuessedPrecision.ABSOLUTE);
    										contact.setCountry(address.getCountry() == null ? getResources()
    												.getConfiguration().locale
    												.getCountry() : address
    												.getCountry());
    										contact.setAddressGuessed(false);
    										contact.setIsConfirmed(true);
    										contact.setPhone(address.getPhone());
    										mPhoneContacts.add(contact);
    									}
    								}
    							} catch (JSONException e) {
    								sLogger.error(e.getMessage());
    							}
    						}
    					}
    				}
    			}
    
    			onContactsListCreated();
    		}
    	};
    
    	/*
    	 * carry over from order review activity in case if contact has to be edited
    	 * or order update must happen on this screen
    	 */
    	private PublisherOrder m_publisherOrder;
    	private int m_orderQuantity;
    	private long m_mrchId;
    
    	private SFContact mSelectedAddress;
    	private List<SFContact> mPhoneContacts;
    	private ExpandableListView mContactsListView;
    	private SFContactExpandableListAdapter mContactsListAdapter;
    	private List<MrchShippingOption> m_mrchShippingOptions = new ArrayList<MrchShippingOption>();
    
    	private String m_shippingOptionDesc;
    	private String m_shippingOptionType;
    
    	/* search */
    	private MenuItem searchItem;
    	private SearchView mSearchView;
    	private ImageView closeBtn;
    	private EditText searchEditText;
    	public static boolean isSearchQuery;
    	private String mSearchString;
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.sf_activity_contact_list);
    
    		m_ctx = this;
    
    		// getSupportLoaderManager().initLoader(CONTACT_DATA_LOADER, null,
    		// this);
    
    		// Display home and finish current activity
    		SFActivityUtils.displayHomeAsUp(this);
    
    		getDataFromIntent();
    		mContactsListView = (ExpandableListView) findViewById(R.id.contacts_list);
    		/*
    		 * on child click the action that happens will depend whether contact
    		 * selected is confirmed or not, meaning that the end-user has validated
    		 * address and order can be safely sent to selected address
    		 */
    		mContactsListView.setOnChildClickListener(new OnChildClickListener() {
    			@Override
    			public boolean onChildClick(ExpandableListView parent, View v,
    					int groupPosition, int childPosition, long id) {
    				mSelectedAddress = (SFContact) mContactsListAdapter.getChild(
    						groupPosition, childPosition);
    				/*
    				 * in the event when address precision is below 100% it must be
    				 * validated by the end-user so the CShippingAddressActivity is
    				 * launched first
    				 */
    				Intent exitIntent = null;
    				if (mSelectedAddress.getGuessedPrecision() != SFContact.GuessedPrecision.ABSOLUTE) {
    					exitIntent = new Intent(SFContactsListActivity.this,
    							SFShippingAddressActivity.class);
    					/* pass contact _id */
    					exitIntent.putExtra(
    							SFContactsHolderDB.SFContactColumns._ID,
    							mSelectedAddress.getId());
    					/* selected shipping address for edit */
    					exitIntent.putExtra(SFConstants.SF_SHIPPING_ADDRESS,
    							handleLocalization(mSelectedAddress));
    					/* shipping options */
    					exitIntent.putExtra(
    							SFConstants.MRCH_SHIP_OPTIONS,
    							getIntent().getStringArrayExtra(
    									SFConstants.MRCH_SHIP_OPTIONS));
    					/* order ID ? */
    					exitIntent.putExtra(SFConstants.ORDERID,
    							m_publisherOrder.getOrderId());
    					/* quantity ? */
    					exitIntent.putExtra(SFConstants.ORDER_QUANTITY, getIntent()
    							.getIntExtra(SFConstants.ORDER_QUANTITY, -1));
    					/* mrchId */
    					exitIntent.putExtra(SFConstants.MRCH_ID, getIntent()
    							.getLongExtra(SFConstants.MRCH_ID, -1));
    					/* and finally order */
    					exitIntent.putExtra(SFConstants.SF_ORDER, orderAsString());
    
    					startActivityForResult(exitIntent,
    							SFConstants.SF_REQUEST_CODE_SHIPPING_ADDRESS);
    				} else {/* adding selected address to order */
    					m_publisherOrder.setShippingAddress(mSelectedAddress);
    
    					resetShippingOptions();
    
    					if (m_shippingOptionDesc != null
    							&& m_shippingOptionType != null) {
    						exitIntent = new Intent();
    						exitIntent.putExtra(SFConstants.SF_ORDER,
    								orderAsString());
    						exitIntent.putExtra(
    								SFConstants.SF_SHIPPING_OPTION_DESCRIPTION,
    								m_shippingOptionDesc);
    						exitIntent.putExtra(
    								SFConstants.SF_SHIPPING_OPTION_SHIPPING_TYPE,
    								m_shippingOptionType);
    						setResult(RESULT_OK, exitIntent);
    						finish();
    					}
    				}
    				return false;
    			}
    		});
    
    	}
    
    	@Override
    	protected void onResume() {
    		// register the event of getting locale contacts
    		SFEventManager.subscribe(m_ctx, SFLocaleContactsEvent.class,
    				m_localeContactListEvent);
    
    		// register the event of getting remote contacts
    		SFEventManager.subscribe(m_ctx, SFRemoteContactsEvent.class,
    				m_remoteContactListEvent);
    
    		m_contactNameOverlay = (TextView) LayoutInflater.from(m_ctx).inflate(
    				R.layout.sf_contact_pop_overlay, null);
    		m_contactNameOverlay.setVisibility(View.INVISIBLE);
    		WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
    				LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
    				WindowManager.LayoutParams.TYPE_APPLICATION,
    				WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
    						| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
    				PixelFormat.TRANSLUCENT);
    		WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
    		windowManager.addView(m_contactNameOverlay, lp);
    
    		showProgressDialog(getString(R.string.sf_please_wait),
    				getString(R.string.sf_progress_locale_contact_list));
    
    		// Get all local contacts
    		SFContactDBManager.asyncGetAllLocalContacts(getSession());
    
    		// initializeData();
    		// ctx = this;
    		// mContactsListView.setAdapter(new ContactExpandListAdapter(group,
    		// child, ctx));
    
    		super.onResume();
    	}
    
    	@Override
    	protected void onPause() {
    		// uninstall the event of getting locale contacts
    		SFEventManager.unsubscribe(m_ctx, SFLocaleContactsEvent.class,
    				m_localeContactListEvent);
    
    		// uninstall the event of getting remote contacts
    		SFEventManager.unsubscribe(m_ctx, SFRemoteContactsEvent.class,
    				m_remoteContactListEvent);
    
    		super.onPause();
    	}
    
    	/**
    	 * simply copies street1 into street2 whenever street2 is a mandatory field
    	 * in the address entry
    	 * 
    	 * @param contact
    	 * @return
    	 */
    	private String handleLocalization(PublisherOrderAddress contact) {
    		if (getResources().getBoolean(R.bool.sf_address_street2_required)) {
    			sLogger.debug("not a localized address: " + contact.toString());
    			if (contact.getStreet2() == null) {
    				contact.setStreet2(contact.getStreet1());
    				contact.setStreet1(null);
    			}
    		}
    
    		String convertedAddr = "";
    		try {
    			convertedAddr = contact.toJSON().toString();
    			sLogger.debug("localized address: " + convertedAddr);
    		} catch (JSONException e) {
    			sLogger.error("cannot convert selected address: " + e);
    		}
    
    		return convertedAddr;
    	}
    
    	@Override
    	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    		super.onActivityResult(requestCode, resultCode, data);
    
    		if (requestCode == SFConstants.SF_REQUEST_CODE_SHIPPING_ADDRESS) {
    			if (resultCode == RESULT_OK) {
    				/*
    				 * after a contact had been verified by end-user it's precision
    				 * level is moved to ABSOLUTE
    				 */
    				mSelectedAddress
    						.setGuessedPrecision(SFContact.GuessedPrecision.ABSOLUTE);
    				setResult(RESULT_OK, data);
    				finish();
    			}
    		}
    
    	}
    
    	/**
    	 * carry over the data required by CShippingAddressActivity
    	 */
    	private void getDataFromIntent() {
    		Intent intent = getIntent();
    		String order = intent.getStringExtra(SFConstants.SF_ORDER);
    		String[] mrchShippingOptions = getIntent().getStringArrayExtra(
    				SFConstants.MRCH_SHIP_OPTIONS);
    
    		if (order != null) {
    			try {
    				m_publisherOrder = PublisherOrder.newFromJSON(new JSONObject(
    						order));
    				if (null != mrchShippingOptions) {
    					for (String mrchShippingOption : mrchShippingOptions) {
    						m_mrchShippingOptions
    								.add(MrchShippingOption
    										.newFromJSON(new JSONObject(
    												mrchShippingOption)));
    					}
    				}
    			} catch (JSONException e) {
    				sLogger.error("cannot parse order: " + order);
    				sLogger.error("cannot parse order: " + e);
    			}
    		} else {
    			showWarningDialog("Order failed", "order not found in intent");
    		}
    	}
    
    	/**
    	 * initializes the contacts list adapter
    	 */
    	private void onContactsListCreated() {
    		/* set adapter */
    		mContactsListAdapter = new SFContactExpandableListAdapter(this,
    				mPhoneContacts);
    		mContactsListView.setAdapter(mContactsListAdapter);
    		/* hide the divider */
    		mContactsListView.setDivider(null);
    		/*
    		 * hide indicator, by design it's the first letter of a contact that
    		 * takes place of the indicator
    		 */
    		mContactsListView.setGroupIndicator(null);
    		/*
    		 * make list state expanded - the first time it should display expanded
    		 * list of contacts
    		 */
    		for (int i = 0; i < mContactsListAdapter.getGroupCount(); i++) {
    			mContactsListView.expandGroup(i);
    		}
    
    		/*
    		 * onScrollListener
    		 */
    		mContactsListView.setOnScrollListener(mItemsListScrollListener);
    	}
    
    	// private List<String> group;// 组列表
    	// private List<List<String>> child;// 子列表
    	// private Context ctx;
    	//
    	// private void initializeData() {
    	// group = new ArrayList<String>();
    	// child = new ArrayList<List<String>>();
    	//
    	// addInfo("Andy", new String[] { "male", "138123***", "GuangZhou" });
    	// addInfo("Fairy", new String[] { "female", "138123***", "GuangZhou" });
    	// addInfo("Jerry", new String[] { "male", "138123***", "ShenZhen" });
    	// addInfo("Tom", new String[] { "female", "138123***", "ShangHai" });
    	// addInfo("Bill", new String[] { "male", "138231***", "ZhanJiang" });
    	// }
    	//
    	// private void addInfo(String group, String[] child) {
    	// this.group.add(group);
    	// List<String> childItem = new ArrayList<String>();
    	// for (int i = 0; i < child.length; i++) {
    	// childItem.add(child[i]);
    	// }
    	//
    	// this.child.add(childItem);
    	// }
    
    	/**
    	 * converts order to string
    	 * 
    	 * @return
    	 */
    	private String orderAsString() {
    		String orderAsString = "";
    		try {
    			orderAsString = m_publisherOrder.toJSON().toString();
    		} catch (JSONException e) {
    			e.printStackTrace();
    		}
    		return orderAsString;
    	}
    
    	private void resetShippingOptions() {
    		PublisherOrder order = m_publisherOrder;
    		PublisherOrderAddress cnt = null;
    		try {
    			cnt = PublisherOrderAddress.newFromJSON(new JSONObject(
    					handleLocalization(order.getShippingAddress())));
    			sLogger.debug("order address: " + cnt.toJSON());
    		} catch (JSONException e) {
    			e.printStackTrace();
    		}
    
    		if (m_mrchShippingOptions.size() > 0) {
    			CShippingOptionsAdapter soa = new CShippingOptionsAdapter(
    					getApplicationContext(), getSession().getAppCredentials()
    							.getLocale(), m_mrchShippingOptions, m_mrchId,
    					m_orderQuantity, cnt);
    
    			String shipping = getApplicationContext().getResources().getString(
    					R.string.sf_order_shipping_opt_no_colon);
    
    			sLogger.debug("getSession().getAppCredentials().getLocale(): "
    					+ getSession().getAppCredentials().getLocale());
    			sLogger.debug("soa.getAvailableShipOptions().size(): "
    					+ soa.getAvailableShipOptions().size());
    
    			if (soa.getAvailableShipOptions().size() > 0) {
    				MrchShippingOption item = soa.getAvailableShipOptions().get(0);
    				String shippingDescription = item.getDescription();
    				String shippingType = Character.toString(
    						shippingDescription.charAt(0)).toUpperCase()
    						+ shippingDescription.substring(1);
    				order.setShippingOption(item.getShippingCode());
    				order.setShipping(0.0f);
    				m_shippingOptionDesc = soa.estimatedDeliveryDays(item
    						.getShippingCode());
    				m_shippingOptionType = shippingType + shipping;
    
    				showProgressDialog(
    						getResources().getString(R.string.sf_please_wait),
    						getResources().getString(
    								R.string.sf_progress_update_order));
    
    			} else {
    				showErrorAlertDialog();
    			}
    		}
    	}
    
    	private void showErrorAlertDialog() {
    		AlertDialog.Builder alertDialog = new AlertDialog.Builder(
    				SFContactsListActivity.this);
    		alertDialog.setTitle(R.string.sf_warning_dialog_title);
    		alertDialog.setMessage(R.string.sf_error_no_shipping_options)
    				.setPositiveButton("OK", new DialogInterface.OnClickListener() {
    
    					@Override
    					public void onClick(DialogInterface dialog, int which) {
    						dialog.dismiss();
    					}
    				}).show();
    	}
    
    	@Override
    	public boolean onCreateOptionsMenu(Menu menu) {
    		getMenuInflater().inflate(R.menu.sf_menu_p2r, menu);
    		searchItem = menu.findItem(R.id.p2r_action_search);
    		mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem);
    
    		searchEditText = (EditText) mSearchView
    				.findViewById(R.id.search_src_text);
    		searchEditText.setHintTextColor(getResources().getColor(
    				R.color.sf_button_normal));
    		searchEditText.setHint(R.string.sf_contacts_search_hint);
    
    		SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    		ComponentName searchComponent = new ComponentName(this,
    				SFContactsListActivity.class);
    
    		mSearchView.setSearchableInfo(searchManager
    				.getSearchableInfo(searchComponent));
    		mSearchView.setIconifiedByDefault(true);
    		mSearchView.setSubmitButtonEnabled(false);
    
    		closeBtn = (ImageView) mSearchView.findViewById(R.id.search_close_btn);
    
    		MenuItemCompat.setOnActionExpandListener(searchItem,
    				new MenuItemCompat.OnActionExpandListener() {
    
    					@Override
    					public boolean onMenuItemActionCollapse(MenuItem arg0) {
    						sLogger.debug("search field collapsed");
    						return true;
    					}
    
    					@Override
    					public boolean onMenuItemActionExpand(MenuItem arg0) {
    						sLogger.debug("search field expanded");
    						return true;
    					}
    
    				});
    
    		closeBtn.setOnClickListener(new View.OnClickListener() {
    
    			@Override
    			public void onClick(View v) {
    				searchEditText.setText("");
    			}
    		});
    
    		mSearchView.setOnQueryTextListener(new OnQueryTextListener() {
    
    			@Override
    			public boolean onQueryTextSubmit(String arg0) {
    				return false;
    			}
    
    			@Override
    			public boolean onQueryTextChange(String searchText) {
    				if (searchText.length() > 0) {
    					mSearchString = searchText;
    					sLogger.debug("search text is: " + searchText);
    				} else {
    					mSearchString = null;
    					sLogger.debug("reset list");
    				}
    				return true;
    			}
    		});
    
    		return super.onCreateOptionsMenu(menu);
    	}
    
    	/**
    	 * Invoking this method when the item option of menu selected
    	 */
    	@Override
    	public boolean onOptionsItemSelected(MenuItem item) {
    		// when the top|left icon selected,finish current activity
    		if (item.getItemId() == android.R.id.home) {
    			finish();
    			overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
    			return true;
    		}
    		return super.onOptionsItemSelected(item);
    	}
    
    	private boolean isValidContact(AddressType addressType) {
    		if (addressType == null)
    			return false;
    
    		if (!TextUtils.isEmpty(addressType.getStreet1())
    				&& !TextUtils.isEmpty(addressType.getCity())
    				&& !TextUtils.isEmpty(addressType.getProvince())
    				&& !TextUtils.isEmpty(addressType.getPhone()))
    			return true;
    
    		return false;
    	}
    
    }
    

    <3>编写布局文件sf_view_contact_sort_header.xml。用于展示租名和记录数量。
    <?

    xml version="1.0" encoding="utf-8"?

    > <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:paddingTop="5dp" android:paddingBottom="5dp" android:paddingLeft="@dimen/sf_standard_layout_padding" android:paddingRight="@dimen/sf_standard_layout_padding" android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/sf_contact_sort_by_name" style="@style/SF_MediumBlueBoldTxt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="5dp" android:layout_marginLeft="5dp" android:text="@string/sf_contacts_sorting_txt" /> <TextView android:id="@+id/sf_contact_sort_counter" style="@style/SF_SmallLightGreyTxt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:gravity="right" android:text="@string/sf_contacts_counter_txt" android:visibility="gone" /> </RelativeLayout>


    <4>编写布局文件sf_view_contact_item.xml,用于展示数据的内容:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        style="@style/SF_SelectableSectionBackground"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/sf_activity_background_color"
        android:paddingBottom="5dp"
        android:paddingLeft="@dimen/sf_contact_item_layout_padding"
        android:paddingRight="@dimen/sf_contact_item_layout_padding" >
    
        <LinearLayout
            android:id="@+id/sf_ll_contact_item_divider"
            style="@style/SF_HorizontalDivider"
            android:layout_width="match_parent"
            android:layout_marginBottom="5dp"
            android:orientation="horizontal" />
    
        <include
            android:id="@+id/sf_include_contact_item_photo"
            android:layout_width="65dp"
            android:layout_height="65dp"
            android:layout_alignLeft="@+id/sf_ll_contact_item_divider"
            android:layout_alignTop="@+id/sf_ll_contact_item_divider"
            android:layout_centerHorizontal="true"
            android:layout_centerInParent="true"
            android:layout_centerVertical="true"
            android:layout_marginTop="5dp"
            layout="@layout/sf_view_contact_graphics"
            android:visibility="visible" />
    
        <LinearLayout
            android:id="@+id/sf_ll_contact_item_details"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="5dp"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:layout_marginTop="5dp"
            android:layout_toRightOf="@id/sf_include_contact_item_photo"
            android:gravity="left|center_horizontal"
            android:orientation="vertical" >
    
            <!-- name -->
    
            <TextView
                android:id="@+id/sf_tv_contact_item_name"
                style="@style/SF_MediumBlackTxt"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="left"
                android:ellipsize="end"
                android:singleLine="true"
                android:text="@string/sf_name_placeholder" />
            <!-- name end -->
    
    
            <!-- address -->
    
            <TextView
                android:id="@+id/sf_tv_contact_item_address"
                style="@style/SF_SmallGreyTxt"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="left"
                android:ellipsize="end"
                android:singleLine="false"
                android:text="@string/sf_address_placeholder"
                android:textAlignment="center" />
            <!-- address end -->
    
            <TextView
                android:id="@+id/sf_tv_contact_item_phone"
                style="@style/SF_MediumLightGreyTxt"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:minLines="1"
                android:scrollHorizontally="false"
                android:singleLine="true"
                android:text="@string/sf_adress_type_txt"
                android:visibility="gone" />
        </LinearLayout>
    
    </RelativeLayout>

    <5>编写SFContactExpandableListAdapter.java。继承BaseExpandableListAdapter.java

    package com.snapfish.util;
    
    import java.io.ByteArrayInputStream;
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.TreeMap;
    
    import android.annotation.SuppressLint;
    import android.content.ContentUris;
    import android.content.Context;
    import android.content.res.Resources;
    import android.database.Cursor;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Color;
    import android.net.Uri;
    import android.provider.ContactsContract.Contacts;
    import android.text.TextUtils;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseExpandableListAdapter;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    import com.snapfish.R;
    import com.snapfish.checkout.IUserData;
    import com.snapfish.internal.datamodel.SFContact;
    import com.snapfish.ui.SFContactsListActivity;
    
    public class SFContactExpandableListAdapter extends BaseExpandableListAdapter { // implements
    	// LoaderManager.LoaderCallbacks<Cursor>
    	private static final SFLogger sLogger = SFLogger
    			.getInstance(SFContactsListActivity.class.getName());
    
    	private Context m_ctx;
    	private ViewHolder m_viewHolder;
    	private List<SFContact> mCombinedContacts;
    	private Map<String, List<SFContact>> mSortedContacts;
    
    	public SFContactExpandableListAdapter(Context mContext,
    			List<SFContact> mCombinedContacts) {
    		this.m_ctx = mContext;
    		this.mCombinedContacts = mCombinedContacts;
    		this.mSortedContacts = getSortedContacts();
    		m_viewHolder = new ViewHolder();
    	}
    
    	@Override
    	public int getGroupCount() {
    		return mSortedContacts.size();
    	}
    
    	@Override
    	public int getChildrenCount(int groupPosition) {
    		List<SFContact> children = mSortedContacts
    				.get(getKeyByPosition(groupPosition));
    		return children.size();
    	}
    
    	@Override
    	public Object getGroup(int groupPosition) {
    		List<SFContact> group = mSortedContacts
    				.get(getKeyByPosition(groupPosition));
    		return group;
    	}
    
    	@Override
    	public Object getChild(int groupPosition, int childPosition) {
    		@SuppressWarnings("unchecked")
    		List<SFContact> selectedGroup = (List<SFContact>) getGroup(groupPosition);
    		if (selectedGroup.size() < childPosition)
    			return null;
    
    		return selectedGroup.get(childPosition);
    	}
    
    	@Override
    	public long getGroupId(int groupPosition) {
    		return groupPosition;
    	}
    
    	@SuppressWarnings("unchecked")
    	@Override
    	public long getChildId(int groupPosition, int childPosition) {
    		List<SFContact> childGroup = (List<SFContact>) getGroup(groupPosition);
    		if (null != childGroup && childGroup.get(childPosition) != null)
    			return childPosition;
    
    		return 0;
    	}
    
    	@Override
    	public boolean hasStableIds() {
    		return false;
    	}
    
    	@Override
    	public View getGroupView(int groupPosition, boolean isExpanded,
    			View convertView, ViewGroup parent) {
    		View row = LayoutInflater.from(m_ctx).inflate(
    				R.layout.sf_view_contact_sort_header, parent, false);
    		TextView sortTextView = (TextView) row
    				.findViewById(R.id.sf_contact_sort_by_name);
    		TextView countTextView = (TextView) row
    				.findViewById(R.id.sf_contact_sort_counter);
    		String letter = getKeyByPosition(groupPosition);
    
    		if (groupPosition == 0) {
    			countTextView.setVisibility(View.VISIBLE);
    			countTextView.setText("" + mCombinedContacts.size() + " "
    					+ m_ctx.getString(R.string.sf_contacts_counter_txt));
    		}
    
    		sortTextView.setText("  " + letter);
    		return row;
    	}
    
    	@Override
    	public View getChildView(int groupPosition, int childPosition,
    			boolean isLastChild, View convertView, ViewGroup parent) {
    		SFContact contact = (SFContact) getChild(groupPosition, childPosition);
    		if (contact != null) {
    			// SFContact.ContactAddressType displayType = contact
    			// .getAddressType();
    			String displayName = contact.getName();
    			String displayAddress = getContactAddress(contact);
    
    			View row = LayoutInflater.from(m_ctx).inflate(
    					R.layout.sf_view_contact_item, parent, false);
    
    			// contact name
    			m_viewHolder.m_name = (TextView) row
    					.findViewById(R.id.sf_tv_contact_item_name);
    			m_viewHolder.m_name.setText(displayName);
    
    			// contact address
    			m_viewHolder.m_address = (TextView) row
    					.findViewById(R.id.sf_tv_contact_item_address);
    			m_viewHolder.m_address.setText(displayAddress);
    
    			/* contact address type */
    			m_viewHolder.m_phone = (TextView) row
    					.findViewById(R.id.sf_tv_contact_item_phone);
    
    			// contact photo
    			setContactIcon(row, contact, getKeyByPosition(groupPosition));
    
    			// if (isMultipleAddress(groupPosition, childPosition)
    			// || contact.getGuessedPrecision() ==
    			// SFContact.GuessedPrecision.LOW) {
    			// showAddressType(m_viewHolder.m_phone,
    			// contact.getGuessedPrecision(), displayType);
    			// }
    
    			row.setTag(m_viewHolder);
    			return row;
    		}
    
    		return convertView;
    	}
    
    	/**
    	 * to avoid displaying address type when we do not have matching contacts
    	 * 
    	 * @param groupPosition
    	 * @param childPosition
    	 * @return
    	 */
    	private boolean isMultipleAddress(int groupPosition, int childPosition) {
    		@SuppressWarnings("unchecked")
    		List<SFContact> group = (List<SFContact>) getGroup(groupPosition);
    		SFContact reference = (SFContact) getChild(groupPosition, childPosition);
    		String referenceName = reference.getName();
    		int i = group.size();
    
    		for (int a = 0; a < i; a++) {
    			if (a != childPosition)
    				if (referenceName.equalsIgnoreCase(group.get(a).getName()))
    					return true;
    		}
    		return false;
    	}
    
    	@Override
    	public boolean isChildSelectable(int groupPosition, int childPosition) {
    		return true;
    	}
    
    	/**
    	 * contact icons are of three kinds: image, icon, or warning message
    	 * 
    	 * @param aContact
    	 * @param letter
    	 * @param addrPositiveMatch
    	 */
    	private void setContactIcon(View row, SFContact aContact, String letter) {
    		// TODO guessed precision was not set in the DB - set it up
    		SFContact.GuessedPrecision addrPositiveMatch = aContact
    				.getGuessedPrecision();
    
    		ViewGroup contactImageView = (ViewGroup) row
    				.findViewById(R.id.sf_include_contact_item_photo);
    
    		if (contactImageView != null) {
    			ImageView unverifiedAddress = (ImageView) contactImageView
    					.findViewById(R.id.sf_iv_contact_need_confirmation);
    			LinearLayout noCntPhoto = (LinearLayout) contactImageView
    					.findViewById(R.id.sf_ll_contact_no_photo);
    			TextView cntFirstLetter = (TextView) noCntPhoto
    					.findViewById(R.id.sf_tv_contact_name_letter);
    			ImageView defaultCntIcon = (ImageView) contactImageView
    					.findViewById(R.id.sf_iv_contact_default_photo);
    			defaultCntIcon.setVisibility(View.GONE);
    			cntFirstLetter.setVisibility(View.GONE);
    			noCntPhoto.setVisibility(View.GONE);
    
    			/* get profile photo bitmap to load into ImageView */
    			Bitmap bmp = getProfilePhoto(aContact);
    
    			switch (addrPositiveMatch) {
    			case ABSOLUTE:
    				if (bmp != null) {
    					defaultCntIcon.setVisibility(View.VISIBLE);
    					defaultCntIcon.setImageBitmap(bmp);
    				} else {
    					noCntPhoto.setVisibility(View.VISIBLE);
    					noCntPhoto.setBackgroundColor(Color
    							.parseColor(getRandomColor()));
    					cntFirstLetter.setVisibility(View.VISIBLE);
    					cntFirstLetter.setText(letter);
    				}
    				break;
    			case HIGH:
    				unverifiedAddress.setVisibility(View.VISIBLE);
    				break;
    			case MEDIUM:
    				unverifiedAddress.setVisibility(View.VISIBLE);
    				break;
    			case LOW:
    				break;
    			default:
    				unverifiedAddress.setVisibility(View.VISIBLE);
    				break;
    			}
    		}
    	}
    
    	private void showAddressType(TextView typeView,
    			SFContact.GuessedPrecision precisionLevel,
    			SFContact.ContactAddressType displayType) {
    		Resources r = m_ctx.getResources();
    		// typeView.setVisibility(View.VISIBLE);
    		typeView.setVisibility(View.GONE);
    
    		if (precisionLevel != SFContact.GuessedPrecision.ABSOLUTE) {// not
    																	// verified
    																	// (guessed)
    																	// address
    			typeView.setTextColor(r
    					.getColor(R.color.sf_error_message_txt_color));
    			typeView.setText(r.getString(R.string.sf_verify_address_label));
    		} else if (displayType != null) { // verified address
    			typeView.setText(getAddressType(displayType));
    		}
    	}
    
    	private int colorsUsed;
    
    	/**
    	 * using preset swatches to set background colors in the layout
    	 * 
    	 * @return
    	 */
    	private String getRandomColor() {
    		String[] colorChoises = m_ctx.getResources().getStringArray(
    				R.array.sf_swatches_sp_set);
    
    		if (colorsUsed == colorChoises.length)
    			colorsUsed = 0;
    
    		String colorOut = colorChoises[colorsUsed];
    
    		colorsUsed++;
    		return colorOut;
    	}
    
    	private Bitmap getProfilePhoto(SFContact aContact) {
    		if (aContact.getContactSource().equals(
    				IUserData.EUserDataType.PHONEBOOK)) {
    			InputStream photoStream = getPhotoAsInputSteam(aContact);
    			if (photoStream != null)
    				return BitmapFactory.decodeStream(photoStream);
    		}
    		return null;
    	}
    
    	private String getKeyByPosition(int groupPosition) {
    		int keyPosition = 0;
    		Iterator<String> iter = mSortedContacts.keySet().iterator();
    		while (iter.hasNext()) {
    			String key = iter.next();
    			if (keyPosition == groupPosition) {
    				return key;
    			}
    			keyPosition++;
    		}
    		return null;
    	}
    
    	/**
    	 * extracting first letter of display name
    	 * 
    	 * @return
    	 */
    	private Collection<String> extractFirstLetter() {
    		Collection<String> sortByLetter = new HashSet<String>();
    		int index = mCombinedContacts.size();
    		Collections.sort(mCombinedContacts, new Comparator<SFContact>() {
    
    			@Override
    			public int compare(SFContact lhs, SFContact rhs) {
    				return lhs.getName().compareTo(rhs.getName());
    			}
    		});
    		for (int i = 0; i < index; i++) {
    			char letter = mCombinedContacts.get(i).getName().charAt(0);
    			sortByLetter.add(String.valueOf(letter).toUpperCase());
    		}
    		return sortByLetter;
    	}
    
    	private Map<String, List<SFContact>> getSortedContacts() {
    		List<SFContact> selectedContact = null;
    		mSortedContacts = new TreeMap<String, List<SFContact>>();
    
    		Iterator<String> firstLetter = extractFirstLetter().iterator();
    		while (firstLetter.hasNext()) {
    			String s = firstLetter.next();
    			int index = mCombinedContacts.size();
    			selectedContact = new ArrayList<SFContact>();
    			for (int i = 0; i < index; i++) {
    				String initChar = String.valueOf(mCombinedContacts.get(i)
    						.getName().charAt(0));
    				if (s.equalsIgnoreCase(initChar)) {
    					selectedContact.add(mCombinedContacts.get(i));
    				}
    			}
    			mSortedContacts.put(s, selectedContact);
    		}
    
    		return mSortedContacts;
    	}
    
    	/**
    	 * retrieves address type string from arrays.xml
    	 * 
    	 * @param addressType
    	 * @return
    	 */
    	private String getAddressType(SFContact.ContactAddressType addressType) {
    		String addrTypeOut = "";
    		int arrSize = m_ctx.getResources().getStringArray(
    				R.array.sf_address_type).length;
    		if (arrSize != 0 && arrSize == 3) {
    			switch (addressType) {
    			case TYPE_HOME:
    				addrTypeOut = m_ctx.getResources().getStringArray(
    						R.array.sf_address_type)[0];
    				break;
    			case TYPE_WORK:
    				addrTypeOut = m_ctx.getResources().getStringArray(
    						R.array.sf_address_type)[1];
    				break;
    			case TYPE_OTHER:
    			default:
    				addrTypeOut = m_ctx.getResources().getStringArray(
    						R.array.sf_address_type)[2];
    				break;
    			}
    		} else
    			addrTypeOut = "UNKNOWN";
    
    		return addrTypeOut;
    	}
    
    	private InputStream getPhotoAsInputSteam(SFContact contact) {
    		byte[] data = contact.getContactPhotoData();
    
    		if (data != null) {
    			return new ByteArrayInputStream(contact.getContactPhotoData());
    		}
    
    		return null;
    	}
    
    	@SuppressLint("InlinedApi")
    	private InputStream openPhoto(long contactId) {
    		Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI,
    				contactId);
    		Uri photoUri = Uri.withAppendedPath(contactUri,
    				Contacts.Photo.CONTENT_DIRECTORY);
    		Cursor cursor = m_ctx.getContentResolver().query(photoUri,
    				new String[] { Contacts.Photo.PHOTO }, null, null, null);
    		if (cursor == null) {
    			return null;
    		}
    		try {
    			if (cursor.moveToFirst()) {
    				byte[] data = cursor.getBlob(0);
    				if (data != null) {
    					return new ByteArrayInputStream(data);
    				}
    			}
    		} finally {
    			cursor.close();
    		}
    		return null;
    	}
    
    	private String getContactAddress(SFContact contact) {
    		StringBuilder sb = new StringBuilder();
    		sb.append(contact.getCountry() + " ");
    		sb.append(contact.getProvince() + " ");
    		sb.append(contact.getCity() + " ");
    		sb.append(TextUtils.isEmpty(contact.getStreet1()) ? (TextUtils
    				.isEmpty(contact.getStreet2()) ? (TextUtils.isEmpty(contact
    				.getStreet3()) ? "" : contact.getStreet3()) : contact
    				.getStreet2()) : contact.getStreet1() + "  ");
    		sb.append(contact.getPostalCode() + "
    ");
    		sb.append(contact.getPhone());
    
    		return sb.toString();
    	}
    
    	private static class ViewHolder {
    		TextView m_name;
    		TextView m_address;
    		TextView m_phone;
    	}
    
    }


    注意

    继承BaseExpandableListAdapter需实现对应的方法:

    <1>getGroupId():获取组号

    <2>getChildId():获取子元素编号(位于组中)

    <3>getGroup():获取指定组的组内容

    <4>getChild():依据组和子元素的位置获取子元素内容

    <5>getGroupCount():获取组的数目

    <6>getChildrenCount():获取相应组的子元素的数目

    <7>getGroupView():获取View对象用于显示组内容

    <8>getChildView():依据组和子元素的位置获取View对象用于显示子元素的内容

    <9>hasStableIds():组和子元素是否持有稳定的ID,也就是底层数据的改变不会影响到它们

    <10>isChildSelectable():是否可选择指定位置的子元素



  • 相关阅读:
    移动端轮播图实现
    iterator
    Promise对象和运算符
    xshell报错:The remote SSH server rejected X11 forwarding request. Last login: Fri Dec 2
    linux平台运行jmeter
    linux基础命令
    APP登录之后会将PC的登录信息踢掉
    测试中遇到支付的一个小问题
    谷歌浏览器css不支持12px以下的
    spring setter注入
  • 原文地址:https://www.cnblogs.com/gccbuaa/p/7182884.html
Copyright © 2011-2022 走看看