Back to project page ElyTheme.
The source code is released under:
GNU General Public License
If you think the Android project ElyTheme listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package com.afollestad.cardsui; // w w w . ja v a2 s . c o m import android.content.Context; import android.graphics.Rect; import android.text.TextUtils; import android.util.SparseIntArray; import android.view.MenuInflater; import android.view.MenuItem; import android.view.TouchDelegate; import android.view.View; import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.TextView; import com.afollestad.silk.adapters.SilkCursorAdapter; import com.afollestad.silk.SilkCursorItem; /** * A {@link SilkCursorAdapter} that displays {@link com.afollestad.cardsui.Card} and {@link CardHeader} objects in a {@link CardListView}. * * @author Aidan Follestad (afollestad) */ public class CardCursorAdapter<ItemType extends CardBase<ItemType> & SilkCursorItem<ItemType>> extends SilkCursorAdapter<ItemType> { private final static int TYPE_REGULAR = 0; private final static int TYPE_NO_CONTENT = 1; private final static int TYPE_HEADER = 2; private final static int DEFAULT_TYPE_COUNT = 3; private final SparseIntArray mViewTypes; protected final int mAccentColor; private int mPopupMenu = -1; private Card.CardMenuListener<ItemType> mPopupListener; private final int mLayout = R.layout.list_item_card; private final int mLayoutNoContent = R.layout.list_item_card_nocontent; private final int mLayoutHeader = R.layout.list_item_header; private CardTheme mTheme = CardTheme.Light; /** * Initializes a new CardAdapter instance. * * @param context The context used to inflate layouts and retrieve resources. * @param accentColorRes The color used for header actions and card titles, 0 will specify black. */ public CardCursorAdapter(Context context, int accentColorRes, Class<? extends SilkCursorItem> cls) { super(context, cls); mAccentColor = context.getResources().getColor(accentColorRes != 0 ? accentColorRes : android.R.color.black); mViewTypes = new SparseIntArray(); registerLayout(R.layout.list_item_card_compressed); registerLayout(R.layout.list_item_header_centered); } /** * Used by the CardListView to tell adapters when they've been attached. Used to transfer the card theme. */ public void onListAttached(CardListView list) { mTheme = list.getCardTheme(); if (getCount() > 0) notifyDataSetChanged(); } public static void setupTouchDelegate(Context context, final View menu) { final int offset = context.getResources().getDimensionPixelSize(R.dimen.card_action_touchdelegate); assert menu.getParent() != null; ((View) menu.getParent()).post(new Runnable() { public void run() { Rect delegateArea = new Rect(); menu.getHitRect(delegateArea); delegateArea.top -= offset; delegateArea.bottom += offset; delegateArea.left -= offset; delegateArea.right += offset; TouchDelegate expandedArea = new TouchDelegate(delegateArea, menu); ((View) menu.getParent()).setTouchDelegate(expandedArea); } }); } @Override public final boolean isEnabled(int position) { ItemType item = getItem(position); if (item.isHeader()) return item.getActionCallback() != null; return item.isClickable(); } /** * Sets a popup menu used for every card in the adapter, this will not override individual card popup menus. * You <b>should</b> call this method before adding any cards to the adapter to avoid issues. * * @param menuRes The menu resource ID to use for the card's popup menu. * @param listener A listener invoked when an option in the popup menu is tapped by the user. */ public final CardCursorAdapter<ItemType> setPopupMenu(int menuRes, Card.CardMenuListener<ItemType> listener) { mPopupMenu = menuRes; mPopupListener = listener; return this; } protected Card.CardMenuListener<ItemType> getMenuListener() { return mPopupListener; } @Override public final int getLayout(int index, int type) { CardBase card = getItem(index); if (type == TYPE_NO_CONTENT) { return mLayoutNoContent; } else if (type == TYPE_HEADER) { return mLayoutHeader; } int layout = card.getLayout(); if (layout == 0) { // If no layout was specified for the individual card, use the adapter's set layout layout = mLayout; } return layout; } private void setupHeader(ItemType header, View view) { view.setBackgroundResource(mTheme == CardTheme.Light ? R.drawable.card_header_selector : R.drawable.card_header_selector_dark); TextView title = (TextView) view.findViewById(android.R.id.title); if (title == null) throw new RuntimeException("Your header layout must contain a TextView with the ID @android:id/title."); TextView subtitle = (TextView) view.findViewById(android.R.id.content); if (subtitle == null) throw new RuntimeException("Your header layout must contain a TextView with the ID @android:id/content."); title.setText(header.getTitle()); title.setTextColor(getContext().getResources().getColor(mTheme == CardTheme.Light ? android.R.color.black : android.R.color.white)); if (!TextUtils.isEmpty(header.getContent())) { subtitle.setVisibility(View.VISIBLE); subtitle.setText(header.getContent()); } else subtitle.setVisibility(View.GONE); subtitle.setTextColor(getContext().getResources().getColor(mTheme == CardTheme.Light ? android.R.color.black : android.R.color.white)); TextView button = (TextView) view.findViewById(android.R.id.button1); if (button == null) throw new RuntimeException("The header layout must contain a TextView with the ID @android:id/button1."); if (header.getActionCallback() != null) { button.setVisibility(View.VISIBLE); button.setBackgroundColor(mAccentColor); String titleTxt = header.getActionTitle(); if (TextUtils.isEmpty(header.getActionTitle())) titleTxt = getContext().getString(R.string.see_more); button.setText(titleTxt); } else button.setVisibility(View.GONE); } @Override public View onViewCreated(int index, View recycled, ItemType item) { if (item.isHeader()) { setupHeader(item, recycled); return recycled; } View innerFrame = recycled.findViewById(android.R.id.widget_frame); if (innerFrame != null) { innerFrame.setBackgroundResource(mTheme == CardTheme.Light ? R.drawable.card_selector : R.drawable.card_selector_dark); } TextView title = (TextView) recycled.findViewById(android.R.id.title); if (title != null) onProcessTitle(title, item, mAccentColor); TextView content = (TextView) recycled.findViewById(android.R.id.content); if (content != null) onProcessContent(content, item); ImageView icon = (ImageView) recycled.findViewById(android.R.id.icon); if (icon != null) { if (onProcessThumbnail(icon, item)) { icon.setVisibility(View.VISIBLE); } else { icon.setVisibility(View.GONE); } } View menu = recycled.findViewById(android.R.id.button1); if (menu != null) { if (onProcessMenu(menu, item)) { menu.setVisibility(View.VISIBLE); } else { menu.setOnClickListener(null); menu.setVisibility(View.INVISIBLE); } } return recycled; } @Override public final Object getItemId(ItemType item) { return item.getSilkId(); } @Override public final int getViewTypeCount() { return mViewTypes.size() + DEFAULT_TYPE_COUNT; } /** * Registers a custom layout in the adapter, that isn't one of the default layouts, and that was passed in the adapter's constructor. * <p/> * This must be used if you override getLayout() and specify custom layouts for certain list items. */ public final CardCursorAdapter<ItemType> registerLayout(int layoutRes) { if (layoutRes == mLayout || layoutRes == mLayoutNoContent || layoutRes == mLayoutHeader) return this; if (mViewTypes.get(layoutRes, 0) != 0) { String name = getContext().getResources().getResourceName(layoutRes); throw new RuntimeException("The layout " + name + " is already registered!"); } mViewTypes.put(layoutRes, mViewTypes.size() + DEFAULT_TYPE_COUNT); return this; } @Override public final int getItemViewType(int position) { CardBase item = getItem(position); if (item.getLayout() > 0) { if (mViewTypes.get(item.getLayout()) != 0) return mViewTypes.get(item.getLayout()); else if (mLayout == item.getLayout()) return TYPE_REGULAR; else if (mLayoutNoContent == item.getLayout()) return TYPE_NO_CONTENT; else if (mLayoutHeader == item.getLayout()) return TYPE_HEADER; String name = getContext().getResources().getResourceName(item.getLayout()); throw new RuntimeException("The layout " + name + " is not registered."); } else { if (item.isHeader()) return TYPE_HEADER; else if (TextUtils.isEmpty(item.getContent())) return TYPE_NO_CONTENT; else return TYPE_REGULAR; } } protected boolean onProcessTitle(TextView title, ItemType card, int accentColor) { if (title == null) return false; title.setText(card.getTitle()); title.setTextColor(accentColor); return true; } protected boolean onProcessThumbnail(ImageView icon, ItemType card) { if (icon == null) return false; if (card.getThumbnail() == null) return false; icon.setImageDrawable(card.getThumbnail()); return true; } protected boolean onProcessContent(TextView content, ItemType card) { content.setText(card.getContent()); content.setTextColor(getContext().getResources().getColor(mTheme == CardTheme.Light ? android.R.color.black : android.R.color.white)); return false; } protected boolean onProcessMenu(final View view, final ItemType card) { if (card.getPopupMenu() < 0) { // Menu for this card is disabled return false; } int menuRes = mPopupMenu; if (card.getPopupMenu() != 0) menuRes = card.getPopupMenu(); if (menuRes < 0) { // No menu for the adapter or the card return false; } setupTouchDelegate(getContext(), view); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int menuRes = mPopupMenu; if (card.getPopupMenu() != 0) menuRes = card.getPopupMenu(); // Force the holo light theme on every card's popup menu Context themedContext = getContext(); themedContext.setTheme(mTheme == CardTheme.Light ? android.R.style.Theme_Holo_Light : android.R.style.Theme_Holo); PopupMenu popup = new PopupMenu(themedContext, view); MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(menuRes, popup.getMenu()); popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { if (card.getPopupMenu() > 0 && card.getPopupListener() != null) { // This individual card has it unique menu card.getPopupListener().onMenuItemClick(card, item); } else if (mPopupListener != null) { // The card does not have a unique menu, use the adapter's default mPopupListener.onMenuItemClick(card, item); } return false; } }); popup.show(); } }); return true; } }