I'm using CardView in a CardListView.
I would like to know how to highlight a card item when it's pressed just like in the "CardsLibDemo Extras" application, precisely in the "Card and Weather List" fragment when you press on a card from the "You may know" list ?
P.S. : I'm using API 15 (Android 4.0.4 Ice Cream sandwich) to test this application.
This is my fragment layout :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- You can customize this layout.
You need to have in your layout a `CardView` with the ID `list_cardId` -->
<it.gmariotti.cardslib.library.view.CardListView
xmlns:card="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/rent_list"
android:foreground="?android:attr/selectableItemBackground"
card:list_card_layout_resourceID="#layout/card_row_layout_rent_list" />
</LinearLayout>
Here is the card_row_layout_rent_list.xml :
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<it.gmariotti.cardslib.library.view.CardView
xmlns:card="http://schemas.android.com/apk/res-auto"
android:id="#+id/list_cardId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card:card_layout_resourceID="#layout/card_layout"
style="#style/list_card.base"/>
</LinearLayout>
Here is the card_layout.xml :
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Card visible layout -->
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/card_main_layout"
style="#style/card.main_layout">
<it.gmariotti.cardslib.library.view.component.CardThumbnailView
xmlns:card="http://schemas.android.com/apk/res-auto"
style="#style/card_thumbnail_outer_layout"
android:id="#+id/card_thumbnail_layout"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
card:card_thumbnail_layout_resourceID="#layout/card_image" />
<FrameLayout
android:id="#+id/card_main_content_layout"
android:layout_gravity="right"
style="#style/card.content_outer_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- Compound view for Shadow
If you want to customize this element use attr card:card_shadow_layout_resourceID -->
<it.gmariotti.cardslib.library.view.component.CardShadowView
style="#style/card.shadow_outer_layout"
android:id="#+id/card_shadow_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="#+id/card_content_expand_layout"
style="#style/card.main_contentExpand"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Here is the card_inner_layout_rent_list.xml :
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- This is the base Inner View inside a CardHeader.
You can customize it with your layout xml file and your CardHeader.
You can popolate your elements with CardHeader#setupInnerViewElements(android.view.ViewGroup, android.view.View) method -->
<TextView
android:id="#+id/textViewPrix"
style="#style/card.header_simple_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="2dp"
android:text="#string/card_txtPrix"
android:textColor="#color/blue"
android:textStyle="bold" />
<TextView
android:id="#+id/textViewAdr"
style="#style/card.expand_simple_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="2dp"
android:text="#string/card_txtAdr"
android:textColor="#color/black"
android:textSize="#dimen/card_expend_simple_title_text_size_16sp"
android:textStyle="bold" />
<TextView
android:id="#+id/textViewType"
style="#style/card.expand_simple_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="2dp"
android:text="#string/card_txtType"
android:textColor="#color/black"
android:textSize="#dimen/card_expand_simple_title_text_size_12sp" />
<TextView
android:id="#+id/textViewSup"
style="#style/card.expand_simple_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="1dp"
android:text="#string/card_txtSup"
android:textColor="#color/black"
android:textSize="#dimen/card_expand_simple_title_text_size_12sp" />
<TextView
android:id="#+id/textViewHonor"
style="#style/card.expand_simple_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginTop="0dp"
android:text="#string/card_txtHonor"
android:textSize="#dimen/card_expand_simple_title_text_size_12sp" />
</LinearLayout>
Here is the card_image.xml :
<?xml version="1.0" encoding="UTF-8"?>
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/card_thumbnail_image"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_margin="1dp"
android:layout_weight="0"
android:layout_gravity="center"
android:contentDescription="#string/imageview_desc"
android:orientation="vertical"/>
Finally, here's where I fill CardList (extracted from the fragment class) :
private void initColorCard() {
int listImages[] = new int[]{R.drawable.angry_1, R.drawable.angry_2,
R.drawable.angry_3, R.drawable.angry_4, R.drawable.angry_5};
ArrayList<Card> cards = new ArrayList<Card>();
for (int i = 0; i<5; i++) {
// Create a Card
ColorCard card = new ColorCard(getActivity());
//Set onClick listener
card.setOnClickListener(new Card.OnCardClickListener() {
#Override
public void onClick(Card card, View view) {
Toast.makeText(getActivity(), "Clickable card : " + card.getCardHeader().getTitle(), Toast.LENGTH_SHORT).show();
}
});
// Create a CardHeader
CardHeader header = new CardHeader(getActivity());
// Add Header to card
header.setTitle("" + i);
card.addCardHeader(header);
CardThumbnail thumb = new CardThumbnail(getActivity());
thumb.setDrawableResource(listImages[i]);
card.addCardThumbnail(thumb);
cards.add(card);
}
CardArrayAdapter mCardArrayAdapter = new CardArrayAdapter(getActivity(), cards);
CardListView listView = (CardListView) getActivity().findViewById(R.id.rent_list);
if (listView != null) {
listView.setAdapter(mCardArrayAdapter);
}
}
Any idea what's missing in this code so any pressed card become highlighted ?
If you are using the CardViewNative, you have to customize this style:
<style name="card.native.main_layout_foreground">
<item name="android:foreground">?android:selectableItemBackground</item>
<item name="android:background">#color/card_native_background</item>
<item name="android:layout_marginTop">#dimen/card_main_layout_native_view_margin_top</item>
<item name="android:layout_marginBottom">#dimen/card_main_layout_native_view_margin_bottom</item>
<item name="android:layout_marginLeft">#dimen/card_main_layout_native_view_margin_left</item>
<item name="android:layout_marginRight">#dimen/card_main_layout_native_view_margin_right</item>
</style>
Otherwise, if you are using the old CardView you can read this:
https://github.com/gabrielemariotti/cardslib/blob/master/doc/CARD.md#customize-card-background
Related
I have a ScollView Layout with a FrameLayout that includes two different layouts. If some condition is met, I set one or the other as visible.
dialog_interface_login.xml
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:font="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/color_white"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="#layout/landing_login_view"/>
<include layout="#layout/mobile_login_view"/>
</FrameLayout>
</ScrollView>
My class:
final View v = inflater.inflate(R.layout.dialog_interface_login, container, false);
View mobileLayout = v.findViewById(R.id.mobile_root_view);
View landingLayout = v.findViewById(R.id.landing_root_view);
if (landingLogin) {
mobileLayout.setVisibility(View.INVISIBLE);
landingLayout.setVisibility(View.VISIBLE);
} else {
mobileLayout.setVisibility(View.VISIBLE);
landingLayout.setVisibility(View.INVISIBLE);
}
Inside theese layouts that was set on the include, I have another include:
landing_login_view.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:font="http://schemas.android.com/apk/res-auto"
android:id="#+id/landing_root_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/color_white"
android:paddingLeft="#dimen/twenty_eight_dp"
android:paddingRight="#dimen/twenty_eight_dp"
android:orientation="vertical">
...
<include layout="#layout/sms_login"/>
...
</LinearLayout>
And mobile_login_view.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:font="http://schemas.android.com/apk/res-auto"
android:id="#+id/mobile_root_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/color_white"
android:paddingLeft="#dimen/twenty_eight_dp"
android:paddingRight="#dimen/twenty_eight_dp"
android:orientation="vertical">
...
<include layout="#layout/sms_login"/>
</LinearLayout>
This is my sms_login.xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:font="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/color_white"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="#dimen/fifty_six_dp"
android:layout_marginBottom="#dimen/twelve_dp"
android:background="#drawable/btn_white_enabled">
<br.com.fs.fslogin.ui.support.views.GothamEditText
android:id="#+id/et_phone_number"
style="#style/AppTheme.RectangularEditText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:digits="0123456789"
android:gravity="center"
android:hint="#string/hint_enter_phone"
android:inputType="number|none"
android:maxLength="11"
android:textColorHint="#color/task_done_color"
android:textSize="#dimen/sixteen_sp"
font:name="#string/font_gotham_medium" />
</FrameLayout>
<FrameLayout
android:id="#+id/dialog_error_phone"
android:layout_width="match_parent"
android:layout_height="#dimen/thirty_two_dp"
android:layout_marginBottom="#dimen/twelve_dp"
android:background="#drawable/bg_warning_phone"
android:visibility="gone">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="#dimen/eight_dp"
android:layout_marginStart="#dimen/eight_dp"
android:contentDescription="#null"
android:src="#drawable/ic_error_phone_red" />
<br.com.fs.fslogin.ui.support.views.GothamTextView
android:id="#+id/error_phone_output"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:lineSpacingExtra="#dimen/two_sp"
android:textColor="#color/error_login_phone_color"
android:textSize="#dimen/fourteen_sp"
font:name="#string/font_gotham_medium" />
</FrameLayout>
<FrameLayout
android:id="#+id/btn_sms_login"
android:layout_width="match_parent"
android:layout_height="#dimen/fifty_six_dp"
android:background="#drawable/btn_login_vivo_purple">
<br.com.fs.fslogin.ui.support.views.GothamButton
style="#style/AppTheme.RectangularButton"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="#null"
android:clickable="false"
android:gravity="center"
android:text="#string/btn_login"
android:textColor="#android:color/white"
android:textSize="#dimen/eighteen_sp"
font:name="#string/font_gotham_bold" />
</FrameLayout>
</LinearLayout>
Programmatically, I set some behaviors, such as a mask for the phone field etc.
But these behaviors that are programmatically configured in sms_login.xml will only occur if the layout is set first in my dialog_interface_login.xml. I have the same include, with the same information, but only works on the first one that is defined at ContainerLayout. Even the onclick event does not trigger.
Do you have any idea why? Is it possible to define two different includes?
----- Edited -----
Including some actions done
v.findViewById(R.id.btn_sms_login).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (phoneWatcher.isPhoneNumberValid()) {
String phoneNumber = etPhoneNumber.getText().toString().replaceAll("\\D+", "");
onSuccessClick.OnSuccess(phoneNumber);
LoginInterfaceVivoSyncDialog.this.dismiss();
}
}
});
You should use Visibility.GONE instead of INVISIBLE
You can directly assign id to include block why you made two extra different layouts to give just an id.
I was shocked to see #dimen/twelve_dp (really shocked). What is use of dimens.xml if you are writing twelve_dp there. You can directly write 12dp. It should be generic like space_small or space_large or text_size_small.
Also removed some extra wrapping layouts from your xml.
dialog_interface_login.xml
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/color_white"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
android:id="#+id/landing_root_view"
layout="#layout/sms_login" />
<include
android:id="#+id/mobile_root_view"
layout="#layout/sms_login" />
</FrameLayout>
</ScrollView>
and
final View v = inflater.inflate(R.layout.dialog_interface_login, container, false);
View mobileLayout = v.findViewById(R.id.mobile_root_view);
View landingLayout = v.findViewById(R.id.landing_root_view);
if (landingLogin) {
mobileLayout.setVisibility(View.GONE);
landingLayout.setVisibility(View.VISIBLE);
} else {
mobileLayout.setVisibility(View.VISIBLE);
landingLayout.setVisibility(View.GONE);
}
sms_login.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:font="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/color_white"
android:orientation="vertical">
<br.com.fs.fslogin.ui.support.views.GothamEditText
android:id="#+id/et_phone_number"
style="#style/AppTheme.RectangularEditText"
android:layout_width="match_parent"
android:layout_height="#dimen/fifty_six_dp"
android:layout_gravity="center"
android:layout_marginBottom="#dimen/twelve_dp"
android:background="#drawable/btn_white_enabled"
android:digits="0123456789"
android:gravity="center"
android:hint="#string/hint_enter_phone"
android:inputType="number|none"
android:maxLength="11"
android:textColorHint="#color/task_done_color"
android:textSize="#dimen/sixteen_sp"
font:name="#string/font_gotham_medium" />
<FrameLayout
android:id="#+id/dialog_error_phone"
android:layout_width="match_parent"
android:layout_height="#dimen/thirty_two_dp"
android:layout_marginBottom="#dimen/twelve_dp"
android:background="#drawable/bg_warning_phone"
android:visibility="gone">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="#dimen/eight_dp"
android:layout_marginStart="#dimen/eight_dp"
android:contentDescription="#null"
android:src="#drawable/ic_error_phone_red" />
<br.com.fs.fslogin.ui.support.views.GothamTextView
android:id="#+id/error_phone_output"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:lineSpacingExtra="#dimen/two_sp"
android:textColor="#color/error_login_phone_color"
android:textSize="#dimen/fourteen_sp"
font:name="#string/font_gotham_medium" />
</FrameLayout>
<br.com.fs.fslogin.ui.support.views.GothamButton
android:id="#+id/btn_sms_login"
style="#style/AppTheme.RectangularButton"
android:layout_width="wrap_content"
android:layout_height="#dimen/fifty_six_dp"
android:layout_gravity="center"
android:background="#drawable/btn_login_vivo_purple"
android:clickable="false"
android:gravity="center"
android:text="#string/btn_login"
android:textColor="#android:color/white"
android:textSize="#dimen/eighteen_sp"
font:name="#string/font_gotham_bold" />
</LinearLayout>
Do you have any idea why?
This happens because findViewById(R.id.xyz) returns the first View which has the requested attribute android:id="#+id/R.id.xyz".
Quoting from the documentation on View:
Finds the first descendant view with the given ID, the view itself if the ID matches getId(), or null if the ID is invalid (< 0) or there is no matching view in the hierarchy.
To access the correct View, you'll have to use some property which makes it unique. In your case, for example the value R.id.et_phone_number can be found twice in the FrameLayout. But if you write
View myView = mobileLayout.findViewById(R.id.et_phone_number);
then there will be just one child View of mobileLayout with the requested id.
Your code snippet can be changed as follows:
final View v = inflater.inflate(R.layout.dialog_interface_login, container, false);
View mobileLayout = v.findViewById(R.id.mobile_root_view);
View landingLayout = v.findViewById(R.id.landing_root_view);
if (landingLogin) {
mobileLayout.setVisibility(View.INVISIBLE);
landingLayout.setVisibility(View.VISIBLE);
} else {
mobileLayout.setVisibility(View.VISIBLE);
landingLayout.setVisibility(View.INVISIBLE);
}
setupViewGroup(mobileLayout);
setupViewGroup(landingLayout);
The method setupViewGroup(View layout) should look like this:
private void setupViewGroup(View layout)
{
final EditText etPhoneNumber = layout.findViewById(R.id.et_phone_number);
layout.findViewById(R.id.btn_sms_login).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (phoneWatcher.isPhoneNumberValid()) {
String phoneNumber = etPhoneNumber.getText().toString().replaceAll("\\D+", "");
// ...
}
}
});
}
By calling findViewById() on layout you will get the desired child Views of the ViewGroups which were added by using <include .../>
I am trying to map a List<List<Object>> to a RecyclerView in Android, but the result is totally messed up.
For example, I have a list of list like this (just for explaining, not my real case):
List<List<String>> list = {{a, b, c}, {d, e}, {f, g, h, i}};
the Recyclerview should display like (first row contains three subrows, second has two and the last on has four):
|----a-----|
|----b-----|
|----c-----|
|=======|
|----d-----|
|----e-----|
|=======|
|----f-----|
|----g-----|
|----h-----|
|----i-----|
but the result is not exactly like the above order. some element is duplicated and some disappears. for example:
|----d-----|
|----e-----|
|----c-----|
|=======|
|----d-----|
|----e-----|
|=======|
|----f-----|
|----a-----|
Here is a piece of my code:
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
List<Event> list = eventList.get(position);
if (holder.rows < list.size()) {
holder.rowViewGroup.removeAllViews();
holder.rows = 0;
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
TextView startView = new TextView(context);
startView.setLayoutParams(layoutParams);
Event headEvent = list.get(0);
Calendar startCal = headEvent.getStartCal();
startView.setText(String.format("%tD", startCal));
holder.rowViewGroup.addView(startView);
for (final Event event : list) {
View element = LayoutInflater.from(context).inflate(R.layout.element, null);
//start time view
TextView startTimeView = (TextView)element.findViewById(R.id.eventStartTimeInElement);
Calendar startTimeCal = event.getStartCal();
startTimeView.setText(String.format("%tl:%tM %tp", startTimeCal, startTimeCal, startTimeCal));
//end date time view
TextView endView = (TextView)element.findViewById(R.id.eventEndTimeInElement);
Calendar endCal = event.getEndCal();
endView.setText(String.format("%tD %tl:%tM %tp", endCal, endCal, endCal, endCal));
//title view
TextView title = (TextView)element.findViewById(R.id.eventTitleInElement);
title.setText(event.getTitle());
//member name
Drawable divider = context.getResources().getDrawable(R.drawable.divider);
ImageView dividerView = new ImageView(context);
dividerView.setImageDrawable(divider);
holder.rowViewGroup.addView(dividerView);
holder.rowViewGroup.addView(element);
holder.rows++;
}
}
}
Here is my row.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/recycleViewRow">
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/cardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="0dp"
card_view:cardElevation="2sp"
card_view:cardUseCompatPadding="true"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/rowView"
android:paddingLeft="20dp"
android:paddingRight="20dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/eventStartTimeInRow"
/>
</LinearLayout>
</android.support.v7.widget.CardView>
and element.xml(which is contained by row.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="#+id/eventStartTimeInElement"
android:layout_weight="2" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="#+id/eventEndTimeInElement"
android:gravity="end"
android:layout_weight="1"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="left">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Medium Text"
android:id="#+id/eventTitleInElement"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="right">
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
card_view:cardCornerRadius="2dp"
card_view:cardElevation="2sp"
card_view:cardUseCompatPadding="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="#+id/memberNameInElement"
android:gravity="end"
/>
</android.support.v7.widget.CardView>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
And I know this is not a really good idea to implement this, so could anybody please tell me a better way to implement this? Thanks...
I think your best bet is to flatten your list of lists into one list.
This is just for purposes of the ListView. Your adapter will act as though the lists have all been strung into one long list.
Start by creating a single-list index for all the items of your nested lists.
For example:
List<List<String>> listOfLists = ... // your original data
List<String> listForView = new ArrayList<String>();
for (List<String> innerList : listOfLists) {
for (String str : innerList) {
listForView.add(str);
}
listForView.add("---"); // e.g. marker value for divider
}
Now in your adapter's getItem() need only return listForView.get(position).
Anytime your nested list structure changes, you redo this flattening operation and call notifyDataSetChanged().
Things get a little trickier if — given the position — you have to figure out which list an item is in, but you could always index the inner lists in a similar fashion.
I have a linearlayout like this
<LinearLayout
android:id="#+id/optionlist"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/divider"
android:orientation="vertical" >
</LinearLayout>
I want to add another xml view into this layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/option"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<!--
<View
android:layout_width="match_parent"
android:layout_height="0.5dip"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="#2fd275"
/>
-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp" >
<ImageView
android:id="#+id/option_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="#drawable/logout" />
<TextView
android:id="#+id/option_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#000000"
android:visibility="gone" />
<TextView
android:id="#+id/option_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="10dp"
android:text="Signout"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#616161" />
</LinearLayout>
<View
android:id="#+id/divider"
android:layout_width="match_parent"
android:layout_height="0.5dip"
android:background="#d3d3d3" />
</LinearLayout>
via the code
for (int i = 0; i < opt.length; i++) {
View view = inflater.inflate(R.layout.option_item, optionlist,
false);
view.setBackgroundResource(R.drawable.optionlist);
view.setTag(opt_image[i]);
view.setClickable(true);
view.setFocusable(true);
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// ADD your action here
int res = (Integer) v.getTag();
switch (res) {
case R.drawable.logout:
signout();
break;
}
}
});
final TextView tv = (TextView) view.findViewById(R.id.option_name);
final ImageView iv = (ImageView) view
.findViewById(R.id.option_image);
tv.setText(opt[i]);
iv.setImageResource(opt_image[i]);
optionlist.addView(view);
}
Now on click of the layout i want to load this xml file as below...but i am not able to get the backgroud loaded on the click event. Please give suggestion what am I doing wrong?
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/holo_green_dark" android:state_focused="true"/>
<item android:drawable="#color/holo_green_dark" android:state_enabled="false" android:state_pressed="true"/>
<item android:drawable="#color/white"/>
</selector>
First get id of LinearLayout from xml and then perform onClickListener on it instead of whole View
View view = inflater.inflate(R.layout.option_item, optionlist, false);
LinearLayout layout = view.findViewByIt(R.id.optionlist);
layout.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// ADD your action here
int res=(Integer) v.getTag();
switch(res)
{
case R.drawable.logout: signout();
break;
}
}
});
try this.. hope it works..
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="#ff0000" />//ur onclick desired color
<item android:state_focused="false"
android:drawable="#android:color/transparent" />focused color
</selector>
just create new xml and add this code in drawable and set ur linear layoyut backgrout as its name like android:background="#drawable/createdxmlname"
<LinearLayout
android:id="#+id/optionlist"
android:layout_below="#id/divider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#drawable/createdxmlname"
android:clickable="true">
android:clickable="false"
<LinearLayout
android:id="#+id/parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageButton
android:clickable="false"
android:layout_width="40dp"
android:layout_height="40dp"
android:text="Cinema"
android:textSize="13sp"
android:layout_marginRight="10dp" />
<Button
android:clickable="false"
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="Check in"
android:textSize="13sp" />
</LinearLayout>
Create in drawable an pressed_layout.xml with the following content
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="#drawable/button_pressed" /> <!-- pressed -->
<item android:state_focused="true"
android:drawable="#drawable/button_focused" /> <!-- focused -->
<item android:drawable="#drawable/button_normal" /> <!-- default -->
</selector>
And in your layout add it as background resource:
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:background="#drawable/pressed_layout"
android:clickable="true">
</LinearLayout>
layout.setclickble="true" in XML file and
layout.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View arg0) {
// TODO Auto-generated method stub
}
});
We can also use onClick in XML of layout,and use that method in java file,like if onClick="next",then in java file we have to use the method .
public void next()
{
// do something
}
I am trying to use
android:background="?android:attr/selectableItemBackground"
to get my button to do appropriate effects for each android version like rippling, etc.
But this produces a button with a grey color when I need a different color.
How can I override this default color ?
If you read the source code of Button.java then you will see that it is a subclass of TextView.java. I have made a simple workaround for the problem in question.
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:background="#1f5050">
<TextView android:layout_width="some_dp"
android:layout_height="some_dp"
android:id="#+id/button"
android:background="?android:selectableItemBackground" />
</LinearLayout>
In code:
button.setOnClickLisetener(new Onclicklistener() {
// do your stuff here
}
It would be much better if someone can extend the TextView class and make a custom Button with the feature in question.
Note: my minsdk is 14. also, the lollipop ripple effect works just fine
Just move your desired color in outer/parent level, e.g. "#color/Red" is button color:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/Red"
android:layout_weight="1">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:gravity="center"
android:text="Hello"
android:textColor="#color/White"/>
</LinearLayout>
Using this method, you can customize ripple effect color. First, you have to create an xml file in your drawable resource directory. Create a ripple_effect.xml file and add following code. I use background colour as Red.
res/drawable/ripple_effect.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:color="#af0c0e"
tools:targetApi="lollipop">
<item android:id="#android:id/mask">
<shape android:shape="rectangle">
<solid android:color="#af0c0e" />
</shape>
</item>
</ripple>
And set background to above drawable resource file. Final code of xml layout activity looks like this.
res/layout/ripple_animation.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:paddingBottom="30dp"
app:cardBackgroundColor="#e7e7e7"
android:id="#+id/cardview"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:background="#drawable/ripple_effect">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_marginRight="16dp"
android:layout_marginLeft="16dp"
android:paddingBottom="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pending"
android:layout_weight="1"
android:layout_marginBottom="2dp"
android:textSize="25dp"
android:textColor="#d11010"
android:id="#+id/txtpending" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Assigned to:"
android:layout_marginLeft="20dp"
android:textColor="#ff000000"
android:id="#+id/txtassigned"
android:layout_weight="1"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="5dp"
android:paddingTop="5dp"
android:layout_marginLeft="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Student Name"
android:id="#+id/txtstudentname"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Student Number"
android:id="#+id/txtstudentnumber"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Parent Name"
android:id="#+id/txtparentname"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Parent Number"
android:id="#+id/txtparentnumber"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Transfer Status"
android:id="#+id/txttransfer"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
Now,ripple effect is Red colour.
if you want to do it programmatically:
fun setSelectableBgWithColor(view: View, bgColor: Int? = null) {
val bgSelectable = getDrawableResCompat(view.context, android.R.attr.selectableItemBackground)
val bg = if (bgColor == null) bgSelectable else LayerDrawable(
arrayOf(ColorDrawable(color), bgSelectable)
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
view.background = bg
} else {
view.setBackgroundDrawable(bg)
}
}
fun getDrawableResCompat(context: Context, #AttrRes id: Int): Drawable? {
return TypedValue()
.also { context.theme.resolveAttribute(id, it, true) }
.let {
val resId = if (it.resourceId != 0) it.resourceId else it.data
ContextCompat.getDrawable(context, resId)
}
}
Edit: this is now possible using AppCompat and backgroundTint
android:backgroundTint="#color/yourColor"
Previous solution:
I had the same problem and ended up doing this programmatically:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ColorStateList colors = new ColorStateList(new int[][]{
new int[]{android.R.attr.state_enabled},
}, new int[]{pressed});
GradientDrawable item = new GradientDrawable();
item.setCornerRadius(radius);
item.setColor(normal);
RippleDrawable ripple = new RippleDrawable(colors, item, null);
button.setBackgroundDrawable(ripple);
} else {
StateListDrawable stateListDrawable = new StateListDrawable();
GradientDrawable item;
item = new GradientDrawable();
item.setCornerRadius(radius);
item.setColor(pressed);
stateListDrawable.addState(new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}, item);
item = new GradientDrawable();
item.setCornerRadius(radius);
item.setColor(normal);
stateListDrawable.addState(new int[]{android.R.attr.state_enabled}, item);
button.setBackgroundDrawable(stateListDrawable);
}
Instead of using ?android:attr/selectableItemBackground you can create a xml in drawable in folder with following content.
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:dither="true">
<item
android:state_pressed="true"
android:drawable="#color/orange"/>
<item
android:state_enabled="false"
android:drawable="#color/default"/>
<item
android:drawable="#color/default"/>
</selector>
Updated: so you save this files as btn_drawable.xml in drawable folder.
Simply replace ?android:attr/selectableItemBackground with #drawable/btn_drawable.xml
I am developing a app In which I reuse a child-layout multiple times in another layout.
In my child layout there is only 1 button.
My question is that..
How can I access a View of child layout as a different.
like for example I access child layout 3 time in Parent layout.
then it shows 3 buttons in Parent layout on run time.
I want to call different activities from these buttons.
My child layout
<RelativeLayout
android:id="#+id/mylayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_margin="30dp"
android:orientation="horizontal" >
<Button
android:id="#+id/bt1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:src="#drawable/chemistry" />
</RelativeLayout>
My Parent Layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/login_bg" >
<HorizontalScrollView
android:id="#+id/horizontalScrollView1"
android:layout_width="fill_parent"
android:layout_height="470dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/lol"
android:orientation="horizontal" >
</LinearLayout>
</HorizontalScrollView>
Java Code--
LinearLayout rl= (LinearLayout)findViewById(R.id.lol);
LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
ArrayList<String> as= getIntent().getExtras().getStringArrayList("dis");
Object[] mstring= as.toArray();
int x= mstring.length;
for (int i=0;i<x; i++ ){
View childLayout = inflater.inflate(R.layout.despage,
(ViewGroup) findViewById(R.layout.despage));
rl.addView(childLayout);
You can add an id to each include like this
<include android:id=”#+id/child1”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
layout=”#layout/child”/>
<include android:id=”#+id/child2”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
layout=”#layout/child”/>
<include android:id=”#+id/child3”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
layout=”#layout/child”/>
Then from the Activity you can retrieve each child and its content with:
View child1 = findViewById(R.id.child1);
Button button1 = child1.findViewById(R.id.someButtonInsideChildLayout);
View child2 = findViewById(R.id.child2);
Button button2 = child2.findViewById(R.id.someButtonInsideChildLayout);
..
Probably you can solve your problem in a better way using styles (eg. one style in values/styles.xml applied to 3 buttons inside the main layout).
Edit (after code attached to the question)
You can access each button inside the for loop with
Button button = childLayout.findViewById(R.id.bt1);
I think this is what you want to do:
parent.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="#layout/child"
android:text="Button 1">
</Button>
<Button
android:id="#+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="#layout/child"
android:text="Button 2"
>
</Button>
<Button
android:id="#+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="#layout/child"
android:text="Button 3" >
</Button>
</LinearLayout>
child.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
findViewById(R.id.btn1).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "Clicked on button 1",Toast.LENGTH_SHORT).show();
}
});
findViewById(R.id.btn2).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "Clicked on button2",Toast.LENGTH_SHORT).show();
}
});