In my XML file I have layout for my fragment which contains HorizontalScrollView like this:
<HorizontalScrollView
android:id="#+id/srollview_seasons_gallery
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="left">
</HorizontalScrollView>
In separate XML file called season_list_item I've made a schema how single item should look like:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/season_image"
android:layout_marginLeft="7dp"
android:layout_marginRight="7dp"
android:onClick="seasonItemClicked"/>
</RelativeLayout>
I add items dynamically with my java code like this:
for (int i=0; i<seasonsSize; i++) {
View vi = ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.season_list_item, null);
ImageView seasonImage = (ImageView) vi.findViewById(R.id.season_image);
//seasonImage.setId(i);
String imgUrl = response.body().getEmbedded().getSeasons().get(i).getImage().getMedium();
Picasso.with(getContext()).load(imgUrl).into(seasonImage);
seasonsLinearLayout.addView(vi);
}
seasonsScrollView.addView(seasonsLinearLayout);
And when I execute my onClick method:
public void seasonItemClicked(View view) {
}
I get error
java.lang.IllegalStateException: Could not find method seasonItemClicked(View) in a parent or ancestor Context for android:onClick attribute defined on view class android.support.v7.widget.AppCompatImageView with id 'season_image'
Uncommenting this line //seasonImage.setId(i); gives me error
android.content.res.Resources$NotFoundException: Unable to find resource ID #0x0`
Pictures are added to layout correctly, just like I want them to. But I cannot achieve to make them clickable. I also find seasonImage.setId(i) important in my case since I need number of the picture that was clicked for further actions.
Could you help me out how this should be approached?
The problem is android:onClick which call your method seasonItemClicked(). As many views you have with this attribute, they will all call this same method, but with the same ID android:id="#+id/season_image".
The setId method could be very annoying because you have to set an unique id. There is some method to generate it, so, for each image, you have to generate an unique ID, and if you set it dynamically, don't set it by xml.
However, assuming that your number of images can be variable, I'd prefer to add the click listener programmatically in the for-loop. That way, they will be related to the imageview clicked. As follows:
for (int i=0; i<seasonsSize; i++) {
...
ImageView seasonImage = (ImageView) vi.findViewById(R.id.season_image);
seasonImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// perform your actions, be aware that 'view' here, is the image clicked
}
}
...
seasonsLinearLayout.addView(vi);
}
And just remove the android:onclick attribute:
<ImageView
...
android:id="#+id/season_image"
android:layout_marginLeft="7dp"
android:layout_marginRight="7dp"/>
You are assigning conflicting ids, ids that are already assigned to other resources. The best way to generate ids for programmatically created views is to use View.generateViewId or reserve them in the res/values/ids.xml file.
Related
I'm making an app where I want to display I want to display all the attachments. But can view only one attachment. Below is the function along with the XML :
//this is the function that displays attachments:
public void showAttachments(List<Attachment> attachments) {
mAttachmentsLayout.setVisibility(View.VISIBLE);
for (Attachment attachment : attachments) {
View view = getLayoutInflater().inflate(R.layout.attachment_item_layout, mAttachmentsLayout, true);
view.setTag(attachment);
//inflating the layout xml file
TextView attachmentTitle = (TextView)view.findViewById(R.id.attachment_title);
String title = attachment.getFileName();
//getFileName() returns the name of the attachment
if (TextUtils.isEmpty(title)) {
title = attachment.getFileName();
}
//assigning title to textview:
attachmentTitle.setText(title);
//want to display all attachments
//not just one
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mBasePermissionPresenter.onClickAttachment((Attachment)v.getTag());
}
});
}
}
Attachments container size increases but only one attachment name is shown
This is the corresponding XML file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/attachmentHeading"
android:padding='#dimen/posting_details_attachment_item_padding'
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/black"
android:id="#+id/attachment_title"/>
</LinearLayout>
I know the solution is really easy but please help out. Thanks.
You are able to only single attachment because you are inflating the same view every time in this fragment of code:
View view = getLayoutInflater().inflate(R.layout.attachment_item_layout, mAttachmentsLayout, true);
You can get your desired result in two ways:
Create different layout.xml for every Image (This will be a lot of work)
or you can add image at run time
I would go with the second option. Do not set your image in the xml file instead add the image at runtime. The code goes as follows:
ImageView imView=(ImageView)view.findViewById(Your_Image_View_ID_here);
imView.setImageResource(Your_Resource_File_ID_Here);
And change the Resource_Id as the loop increments.
Have fun :)
I´m working on two layouts: the main one and another one (a card layout). I included the card layout inside the main layout, with the following code:
<include
android:id="#+id/miPrueba"
layout="#layout/card_product_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:elevation="10dp"
android:layout_margin="15dp"/>
This works fine, but I have buttons in my main layout and I need to use them. When I try to find them, using findViewByIdid from my card layout, I use this code:
View view = LayoutInflater.from(getApplication()).inflate(R.layout.card_product_details, null);
Button prueba = (Buttton) view.findViewById(R.id.buttonId);
prueba.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Toast por defecto", Toast.LENGTH_SHORT).show();
}
});
What I get is nothing, no error, no null pointer exception, nothing. Simple, it does not respond when I click it.
How I can solve it?
Need more of your code but from what you have given the reason you are having this problem is that the card doesn't have the button buttonId
When you are creating
View view = LayoutInflater.from(getApplication()).inflate(R.layout.card_product_details, null);
I have created an Activity that uses the ViewFlipper to Switch between Different elements. Each element represents an Item in a store. I would like to add a "Buy" Button to each View. I am however not sure how to do this, since all the views use the default layout i have created. I have added the information like the Price of the Item etc Programmatically. So i am uncertain how to add a listener to the button, since they will all refer to the same button in the xml file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<Button
android:id="#+id/credit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="220dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginTop="104dp" />
<TextView
android:id="#+id/credit_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="#+id/credit_button"
android:layout_alignTop="#+id/credit_button"
android:layout_marginRight="22dp"
android:layout_marginTop="21dp"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge"
android:typeface="normal" />
<TextView
android:id="#+id/credit_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/credit_button"
android:layout_alignRight="#+id/credit_type"
android:layout_centerVertical="true"
android:layout_marginBottom="30dp"
android:layout_marginLeft="15dp"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
As you can see, the Button id is "Credit Button". So now to be able to differentiate between the different store items' buttons what would i have to do?
Note, i am adding store items dynamically as well, so i cant simply create all the views separately using xml.
OK HERE IS THE UPDATED ANSWER. I used everyones responses below to fix teh issue. So Thank you all :)
// PerkView
View PerkView = View.inflate(this, R.layout.store_category, null);
viewFlipper.addView(PerkView);
Button perkButton = (Button)
PerkView.findViewById(R.id.StoreCatItem);
// TitleView
View TitleView = View.inflate(this, R.layout.store_category, null);
viewFlipper.addView(TitleView);
Button titleButton = (Button)
TitleView.findViewById(R.id.StoreCatItem);
// ProfileView
View ProfileView = View.inflate(this, R.layout.store_category, null);
viewFlipper.addView(ProfileView);
Button profileButton = (Button)
ProfileView.findViewById(R.id.StoreCatItem);
I simply Created Multiple Views Programmatically, and then retrieved the buttons from those views afterwards. I then added the listeners to the buttons as follows:
perkButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent i = new Intent(getBaseContext(), Perks.class);
i.putExtra("player", player);
startActivity(i);
}
});
titleButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent i = new Intent(getBaseContext(), Titles.class);
i.putExtra("player", player);
startActivity(i);
}
});
Thanks A lot :)
There are two ways you can handle the button click distinctly,
At the time of inflating layout for each store, add the button listener with onClick() method there only.
Or you can assign some uniqueId or flag to each store and then handle button click of store by this uniqueID.
Usually you solve this by following stack:
fragment -has-> list -has-> adapter -has-> list of items
Normally if you present one item per screen and you want to swipe between you should use ViewPager with FragmentStatePagerAdapter (allows removing items from ViewPager if needed).
http://developer.android.com/reference/android/support/v4/view/ViewPager.html
For more items in one screen use ListView with BaseAdapter as it allows better control over item view and ListView will recycle views as you scroll or fling.
http://developer.android.com/guide/topics/ui/layout/listview.html
Set unique tag for each store button, in code you can differentiate with respect to tags.Tag is just piece of information you want set for any view, u can use it.Implement on click listener in your activity and then set that to all buttons, so all buttons click run through same code where you can easily diffrentiate between ur store buttons with respect to tags.
like below how you can set and get tag
// for setting tag
Button button = (Button) findViewById(R.id.button1);
button.setTag("unique_tag");
// get tag and then differentiate with the unique_tg
button.getTag();
You can easily create your button programmatically like so :
Button b = new Button(this); // where this = your context
b.setText("Buy");
// b."other attribute" = "other value";
b.setTag("Awesome blue shirt");
b.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Button buy = (Button) v;
String article = b.getTag();
// do some stuff
}
});
container.addView(b);
You can identify the buy button using its tag, as seen here.
I would like to create a linear layout which would behave similarly to ImageButton.
<LinearLayout
android:id="#+id/container"
style="?WidgetHomeIconContainer">
<ImageView
android:id="#+id/icon"
style="?WidgetHomeIcon" />
<TextView
android:id="#+id/title"
style="?WidgetHomeLabel"
android:text="#string/title"
android:textAppearance="?attr/TextHomeLabel" />
</LinearLayout>
In styles of ImageView, TextView and LinearLayout, I set a selectors for all states.
Now:
when I click on ImageView (I tried it also with ImageButton) - it behaves correctly and the image is changed according the selector xml.
when I click on LinearLayout - the linear layout is clicked, but the the ImageView and TextView don't change it's drawable/appearance
So I would like to do the following. When I click on parent LinearLayout, I need to change all it's childs to pressed state.
I tried to add following code to LinearLayout onClickListener to propagate the click:
#Override
public void onClick(View v)
{
LinearLayout l = (LinearLayout) v;
for(int i = 0; i < l.getChildCount(); i++)
{
l.getChildAt(i).setClickable(true);
l.getChildAt(i).performClick();
}
}
But it still reamins the same. Thank you very much for any help.
Put
android:duplicateParentState="true"
in your ImageView and TextView..then the views get its drawable state (focused, pressed, etc.) from its direct parent rather than from itself.
Not only make for every child:
android:duplicateParentState="true"
But also additionally:
android:clickable="false"
This will prevent unexpected behaviour (or solution simply not working) if clickable child views are used.
SO Source
After having the same problem some months later, I found this solution:
private void setOnClickListeners() {
super.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
onClick(v);
}
});
for (int index = 0; index < super.getChildCount(); index++) {
View view = super.getChildAt(index);
view.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
onClick(v);
}
});
}
}
protected void onClick(View v) {
// something to do here...
}
In my case, no one of the other solutions works!
I finally had to use OnTouchListener as explained here, capturing the event when the user clicks in the parent view, and removing all childs OnClickListener.
So the idea is, delegate the click behavior to the parent, and notify the child that is really clicked, if you want to propagate the event. ¡¡That's what we are looking for!!
Then, we need to check which child has been clicked. You can find a reference here to know how it´s done. But the idea is basiclly getting the area of the child, and asking for who contains the clicked coordinates, to perform his action (or not).
At first, my child view failed to get click from parent. After investigating, what I need to do to make it work are:
remove click listener on child view
adding click listener on parent view
So, I don't need to add these on every children.
android:duplicateParentState="true"
android:clickable="false"
I only add duplicateParentState to one of my child view.
My child view is now listening to parent click event.
It looks like a kind of wrong approach, but I'd still ask.
The task is, you have a layout xml that describes a composite widget (like Button + TextView). You'd like to make it re-usable, so you build a class like MyTextViewButtonWidget - it will expose its button text accessors and it will also do the same for text view:
public class MyTextViewButtonWidget extends LinearLayout {
...
void setButtonText(String text) { ... }
String getButtonText() { ... }
void setTextViewText(String text) { ... }
String getTextViewText() { ... }
...
}
Layout definition looks like this:
<LinearLayout ..........>
....button and text label here...
</LinearLayout>
The question is - how would you load this layout so that its root LinearLayout would be the LinearLayout part of MyTextViewButtonWidget?
Tried defining MyTextViewButtonWidget's ctor like this:
{
inflate(getContext(), R.layout.reusable_widget_layout, this);
}
But this loads reusable_widget_layout as a child to MyTextViewButtonWidget (that's not what I need).
Generally, the problem is:
You need to create a composite widget
You'd like to be able to define its layout with xml markup
You'd like it to load root's child widgets defined in xml as its child widgets (INSTEAD OF: load the whole hierarchy from xml as a single child of your reusable widget)
Replace:
<LinearLayout ..........>
....button and text label here...
</LinearLayout>
with:
<merge ..........>
....button and text label here...
</merge>