In this page you can find info about:
- Creating a base Card
- Use your custom card-layout
- Use your content inner layout
- Extending Card class
- Listeners
- Card with a swipe action
- Clickable card
- ClickListener on a specific area
- Refresh a card
- Replace inner layout in a card
- Customize Card background
- Change Dynamically card background
- Change dynamically Card background with a Drawable object
- Export card as bitmap
- Using Card with contextual action mode
- Using a ForegroundLinearLayout
Creating a Card
is pretty simple.
First, you need an XML layout that will display the Card
.
<it.gmariotti.cardslib.library.view.CardViewNative
android:id="@+id/carddemo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:layout_marginTop="12dp"/>
Then create a model:
//Create a Card
Card card = new Card(getContext());
//Create a CardHeader
CardHeader header = new CardHeader(getContext());
....
//Add Header to card
card.addCardHeader(header);
Last get a reference to the CardView
from your code, and set your `Card.
//Set card in the cardView
CardViewNative cardView = (CardViewNative) getActivity().findViewById(R.id.carddemo);
cardView.setCard(card);
Card Library provides 2 built-in card layouts.
For the CardViewNative:
res/layout/native_card_layout.xml
: this is the default layout and doesn't contain the thumbnail.res/layout/native_card_thumbnail_layout.xml
: this contains the thumbnail
For the CardView:
res/layout/card_layout.xml
: this is the default layout and doesn't contain the thumbnail.res/layout/card_thumbnail_layout.xml
: this contains the thumbnail
You can easily build your layout.
The quickest way to start with this would be to copy one of this files and create your layout.
Then you can inflate your layout in the CardViewNative
using the attr: card:card_layout_resourceID="@layout/my_layout
Example:
<it.gmariotti.cardslib.library.view.CardViewNative
android:id="@+id/carddemo_thumb_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
card:card_layout_resourceID="@layout/native_card_thumbnail_layout"
android:layout_marginTop="12dp"/>
If you want to preserve built-in features you have to use the same IDs for Compound Views (Header, Shadow, Thumbnail) and Built-in Frame (Content, Expand).
Each component (view or frame) can be easily customize with style/drawable resources or inflating custom inner layout.(See doc about Header,Shadow,Thumbnail,Expand).
Each Card has a content Frame area, where you can display your custom info.
The built-in content inner layout is quite useless, and provides a simple title.
//Create a Card
Card card = new Card(getContext());
//Set the card inner text
card.setTitle("My Title");
//Set card in the cardView
CardViewNative cardView = (CardViewNative) getActivity().findViewById(R.id.carddemo_card_id);
cardView.setCard(card);
Surely you have to custom this area.
To do this you can use the Card
constructor
//Create a Card
Card card = new Card(getContext(),R.layout.carddemo_example_inner_content);
//Set the card inner text
card.setTitle(getString(R.string.demo_card_basetitle));
//Set card in the cardView
CardViewNative cardView = (CardViewNative) getActivity().findViewById(R.id.carddemo_card_id);
cardView.setCard(card);
This is the layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_marginTop="2dp"
android:id="@+id/colorBorder"
android:background="@drawable/rectangle"
android:layout_width="10dp"
android:layout_height="@dimen/card_base_empty_height"/>
<!-- Use same ID to use built-in features -->
<TextView
android:layout_toRightOf="@id/colorBorder"
android:id="@+id/card_main_inner_simple_title"
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
The layout above is quite simple, and doesn't need to set values.
If you want to have a full control on the main content, you can extend Card
class, inflate your custom inner layout and then set your values with setupInnerViewElements
method.
public class CustomCard extends Card {
protected TextView mTitle;
protected TextView mSecondaryTitle;
protected RatingBar mRatingBar;
/**
* Constructor with a custom inner layout
* @param context
*/
public CustomCard(Context context) {
this(context, R.layout.carddemo_mycard_inner_content);
}
/**
*
* @param context
* @param innerLayout
*/
public CustomCard(Context context, int innerLayout) {
super(context, innerLayout);
init();
}
/**
* Init
*/
private void init(){
//No Header
//Set a OnClickListener listener
setOnClickListener(new OnCardClickListener() {
@Override
public void onClick(Card card, View view) {
Toast.makeText(getContext(), "Click Listener card=", Toast.LENGTH_LONG).show();
}
});
}
@Override
public void setupInnerViewElements(ViewGroup parent, View view) {
//Retrieve elements
mTitle = (TextView) parent.findViewById(R.id.carddemo_myapps_main_inner_title);
mSecondaryTitle = (TextView) parent.findViewById(R.id.carddemo_myapps_main_inner_secondaryTitle);
mRatingBar = (RatingBar) parent.findViewById(R.id.carddemo_myapps_main_inner_ratingBar);
if (mTitle!=null)
mTitle.setText(R.string.demo_custom_card_google_maps);
if (mSecondaryTitle!=null)
mSecondaryTitle.setText(R.string.demo_custom_card_googleinc);
if (mRatingBar!=null)
mRatingBar.setNumStars(5);
mRatingBar.setMax(5);
mRatingBar.setRating(4.7f);
}
}
Then you can simply do:
//Create a Card
Card card = new CustomCard(getActivity());
//Set card in the cardView
CardViewNative cardView = (CardViewNative) getActivity().findViewById(R.id.carddemo_example_card3);
cardView.setCard(card);
The Card
class provides some listeners to handle callbacks.
OnSwipeListener
: invoked when the card is swipedOnCardClickListener
: invoked when the card is clickedOnLongCardClickListener
: invoked when the card is long clickedOnExpandAnimatorStartListener
: invoked when the expand animation startsOnCollapseAnimatorStartListener
: invoked when the collapse animation startsOnExpandAnimatorEndListener
: invoked when the expand animation endsOnCollapseAnimatorEndListener
: invoked when the collapse animation ends
See Card Header: for Header listeners.
If you want to enable the swipe action on a Card
is very simple:
//Create a Card
Card card = new CustomCard(getActivity());
//Enable a swipe action
card.setSwipeable(true);
//Set card in the cardView
CardViewNative cardView = (CardViewNative) getActivity().findViewById(R.id.carddemo_example_card3);
cardView.setCard(card);
It is not mandatory. You can set a Card.OnSwipeListener
to listen the swipe action.
//You can set a SwipeListener.
card.setOnSwipeListener(new Card.OnSwipeListener() {
@Override
public void onSwipe(Card card) {
//Do something
}
});
If you want a clickable card, enable a Card.OnCardClickListener
//Create a Card
Card card = new CustomCard(getActivity());
//Set onClick listener
card.setOnClickListener(new Card.OnCardClickListener() {
@Override
public void onClick(Card card, View view) {
Toast.makeText(getActivity(),"Clickable card", Toast.LENGTH_LONG).show();
}
});
//Set card in the cardView
CardViewNative cardView = (CardViewNative) getActivity().findViewById(R.id.carddemo_example_card3);
cardView.setCard(card);
With OnCardClickListener
you can set your card as clickable.
If you want to set only a part (or more parts) as clickable you can use this code:
//Set a clickListener on ContentArea
card1.addPartialOnClickListener(Card.CLICK_LISTENER_CONTENT_VIEW, new Card.OnCardClickListener() {
@Override
public void onClick(Card card, View view) {
Toast.makeText(getActivity(),"Click on Content Area", Toast.LENGTH_LONG).show();
}
});
//Set a clickListener on Header Area
card2.addPartialOnClickListener(Card.CLICK_LISTENER_HEADER_VIEW, new Card.OnCardClickListener() {
@Override
public void onClick(Card card, View view) {
Toast.makeText(getActivity(),"Click on Header Area", Toast.LENGTH_LONG).show();
}
});
//Set a clickListener on Thumbnail area
card3.addPartialOnClickListener(Card.CLICK_LISTENER_THUMBNAIL_VIEW, new Card.OnCardClickListener() {
@Override
public void onClick(Card card, View view) {
Toast.makeText(getActivity(),"Click on Thumbnail", Toast.LENGTH_LONG).show();
}
});
If you need to change same value in a card, you can use your Card
model:
card.setTitle("New title");
//Change Header
card.getCardHeader().setTitle("New image");
//Change Thumbnail
card.getCardThumbnail().setDrawableResource(R.drawable.ic_std_launcher);
//Remove click listener
card.setOnClickListener(null);
card.setClickable(false);
and then call notifyDataSetChanged();
method on the Card
:
//Call refresh
card.notifyDataSetChanged();
You can see the example in 'ChangeValueCardFragment'.
If you need to replace the inner layout in a card, you can use your Card
model and call replaceCard
method on cardView
:
//Call replace
card3.setInnerLayout(R.layout.carddemo_suggested_inner_content);
cardView3 = (CardViewNative) getActivity().findViewById(R.id.carddemo_card_changevalue_id3);
cardView3.replaceCard(card3);
In your setupInnerViewElements()
method you should provide the correct way to put values in your ui elements according to the layout.
You can see the example in ChangeValueCardFragment
.
For CardViewNative:
PAY ATTENTION:Don't use with CardViewNative
For CardView:
The quickest way to customize the card background would be to copy the styles/drawables in your project.
Default cards use res/drawable/card_selector.xml
.
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
<item android:state_pressed="true" android:drawable="@drawable/pressed_background_card"/>
<item android:drawable="@drawable/card_background"/>
</selector>
In res/drawable/card_background.xml
and res/drawable/pressed_background_card.xml
you can easy customize the color and shape.
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/card_background"/>
<corners android:radius="@dimen/card_background_default_radius"/>
</shape>
If you want to change the color, the quickest way would be to customize this value in your project:
<color name="card_background">#FFF</color>
If you want to change the rounded corners, the quickest way would be to customize this value in your project:
<dimen name="card_background_default_radius">2dip</dimen>
If you need to change dynamically the card background you can use this code:
For CardViewNative:
PAY ATTENTION:Don't use with CardViewNative (not yet supported).
ColorCard card = new ColorCard(this.getActivity());
//Set Background resource
card.setBackgroundColorResourceId(R.color.demo_card_background_color5);
Where R.color.demo_card_background_color5
is a color.
For CardView:
ColorCard card = new ColorCard(this.getActivity());
//Set Background resource
card.setBackgroundResourceId(R.drawable.demo_card_selector_color1);
Where R.drawable.demo_card_selector_color1 can be a selector or a drawable.
Example:
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
<item android:state_pressed="true" android:drawable="@drawable/pressed_background_card"/>
<item android:drawable="@drawable/demo_card_background_color1"/>
</selector>
You can see this example: Colored cards example (source).
Only for CardView.
Also you can customize your background using a Drawable object:
StateListDrawable newDrawable = new StateListDrawable();
newDrawable.addState(new int[]{android.R.attr.state_pressed},
getResources().getDrawable(R.drawable.pressed_background_card));
newDrawable.addState(new int[] {}, getResources().getDrawable(R.drawable.demo_card_background_color2));
card4setBackgroundResource(newDrawable);
You can see this example: (source).
You can export your Card
as a Bitmap.
It is very simple.
CardViewNative cardView = (CardViewNative) getActivity().findViewById(R.id.myCard);
Bitmap bitmap = cardView.createBitmap();
You can use this bitmap for your scopes.
In BitmapUtils
class there are some built-in methods:
- You can use
File photofile= BitmapUtils.createFileFromBitmap(bitmap)
to save the image inEnvironment.DIRECTORY_PICTURES
folder. - You can use
Intent intent = BitmapUtils.createIntentFromImage(photofile)
to put the image asEXTRA_STREAM
in aIntent
.
You can see the example in BirthDayCardFragment
and StockCardFragment
where you can share the card as a bitmap.
PAY ATTENTION:Don't use with CardViewNative and/or Toolbar (not yet supported)
If you would like to use a card with you can use a code like this:
ActionMode mActionMode;
//Create a Card
Card mCardCab = new Card(getActivity());
//Set the card inner text
mCardCab.setTitle(getString(R.string.demo_card_basetitle));
//Set onClick listener
mCardCab.setOnLongClickListener(new Card.OnLongCardClickListener() {
@Override
public boolean onLongClick(Card card, View view) {
if (mActionMode != null) {
view.setActivated(false);
mActionMode.finish();
return false;
}
// Start the CAB using the ActionMode.Callback defined below
mActionMode = getActivity().startActionMode(mActionModeCallback);
view.setActivated(true);
return true;
}
});
//Set card in the cardView
cardViewCab = (CardView) getActivity().findViewById(R.id.carddemo_example_card_cab);
cardViewCab.setCard(mCardCab);
}
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
// Called when the action mode is created; startActionMode() was called
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Inflate a menu resource providing context menu items
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.carddemo_cab_example, menu);
return true;
}
// Called each time the action mode is shown. Always called after onCreateActionMode, but
// may be called multiple times if the mode is invalidated.
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false; // Return false if nothing is done
}
// Called when the user selects a contextual menu item
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.carddemo_toast:
Toast.makeText(getActivity(), "Change Text",
Toast.LENGTH_LONG).show();
if (mCardCab!=null && cardViewCab!=null){
//Example to change dinamically your card
mCardCab.setTitle(getString(R.string.demo_title_cab2));
cardViewCab.refreshCard(mCardCab);
}
mode.finish(); // Action picked, so close the CAB
return true;
default:
return false;
}
}
// Called when the user exits the action mode
@Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
if (mCardCab!=null)
cardViewCab.setActivated(false);
}
};
You can see this example: (source).
This paragraph is only for CardView. The default layout used by the CardViewNative is a ForegroundLinearLayout.
You can draw the stateful drawable on top, using a foreground selector.
To achieve this behaviour you have to do these steps:
- change the
android:id="@+id/card_main_layout"
element in your card layout
Default layout:
<!-- Standard Card visible layout -->
<LinearLayout
android:id="@+id/card_main_layout"
style="@style/card.main_layout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
Foreground layout:
<!-- Foreground Card visible layout -->
<it.gmariotti.cardslib.library.view.ForegroundLinearLayout
android:id="@+id/card_main_layout"
style="@style/card.main_layout_foreground"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
- change the default style with something like the
style="@style/card.main_layout_foreground"
This style uses a foreground selector using the android:foreground
attribute, and a simple drawable(or color) for background.
<!-- Style for Main Layout with foreground selector-->
<style name="card.main_layout_foreground">
<item name="android:background">@drawable/card_background</item>
<item name="android:foreground">@drawable/card_foreground_selector</item>
</style>
You can see this example: (source).
Pay attention. The default card has a min height.
Check this style:
<style name="card.content_outer_layout">
You can override this value in your dimens.xml:
<dimen name="card_base_empty_height">96dp</dimen>