Click events handling does not work.
Click handling works with CheckBox and TextView, but doest not work with frameLayout.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="#drawable/yellow_ripple"
android:clickable="true"
>
<TextView
android:clickable="false"
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"/>
<CheckBox
android:clickable="false"
android:id="#+id/box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|right"
/>
In create view:
View resultView = LayoutInflater.from(context)
.inflate(R.layout.filter_signle_view, parent, true);
selectedBox = (CheckBox) resultView.findViewById(R.id.box);
title = (TextView) resultView.findViewById(R.id.text);
title.setText(m_filter.getTitle());
selectedBox.setChecked(m_state.isSelected());
selectedBox.setOnCheckedChangeListener((compoundButton, b) ->
m_state.setSelected(b)
);
resultView.setClickable(true);
resultView.setOnClickListener(
view -> m_state.setSelected(!m_state.isSelected())
);
);
return resultView;
I want to handle clicks on FrameLayout. It is not happening.
(I use retrolamda)
You are assigning the listener to the parent of your frame layout.
Please change last parameter of your inflation from true to false. For more - LayoutInflater.inflate(int, ViewGroup, boolean)
View resultView = LayoutInflater.from(context).inflate(R.layout.filter_signle_view, parent, false);
1) Add listener to frame layout. You are missing it and its the most important thing here.
2) Add
android:descendantFocusability="blocksDescendants"
to frame layout in xml. This will prevent child items clicks.
Ok, so after fixing numerous compile errors and other Lint issues, I did run your code (slightly modified). And it worked fine, here's what I have.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="?attr/selectableItemBackground"
android:clickable="true">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:clickable="false" />
<CheckBox
android:id="#+id/box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
android:clickable="false" />
</FrameLayout>
And the Java part...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View resultView = LayoutInflater.from(getActivity()).inflate(R.layout.generator_personalization, container, false);
CheckBox selectedBox = (CheckBox) resultView.findViewById(R.id.box);
TextView title = (TextView) resultView.findViewById(R.id.text);
title.setText("Title!");
selectedBox.setChecked(true);
selectedBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Toast.makeText(getActivity(), "Changed!", Toast.LENGTH_SHORT).show();
}
});
resultView.setClickable(true);
resultView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getActivity(), "CLICKED!", Toast.LENGTH_SHORT).show();
}
});
return resultView;
}
So basically, what I think is the biggest problem here is attaching the view to the parent in your inflate statement. Try changing that last parameter to false.
You should also note that setting click listeners from code also sets the clickable attribute when enabled.
Hope this helps!
P.S. Consider changing that layout to something more maintainable - like using a single CheckBox instead of FrameLayout + TextView + CheckBox without text.
When you infilating a layout, you supply this parameters to the inflator service:
public View inflate(int resource, ViewGroup root, boolean attachToRoot)
If you set attachToRoot true then the returned view is the root view that you suppilied.
In your example you set it to true and it is returning the "parent" view.
You then set a click listener to a parent viewgroup, however, the click event will be consumed on the child FrameLayout because you set the clickable to true. In your case this will do nothing because you set the click listener to the wrong view, and another view consumed the click event.
So you should set the attachToRoot to false, and the returned view will be your FrameLayout, and that will fix your problems.
Related
I'd like to be able to set a View.OnclickListener to an ImageView inside a page (fragment) of my ViewPager, I don't want to click on the whole page of my ViewPager, I just want to be able to click on a specifig ImageView. I followed these questions (onClick not triggered on LinearLayout with child, How to set OnClickListener in ViewPager
) but they did not help me. This is my actual code:
MyPageFragment.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="240dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:focusableInTouchMode="true"
android:id="#+id/container_linear"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop" />
</LinearLayout>
</LinearLayout>
MyActivity.xml
<android.support.v4.view.ViewPager
android:id="#+id/product_view_pager"
android:layout_width="match_parent"
android:layout_height="240dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:gravity="center"
android:overScrollMode="never" />
MyFragment.class (where I'm binding the views using Butterknife)
#BindView(R.id.container_linear)
LinearLayout mContainer;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View mRootView = inflater.inflate(R.layout.my_layout, container, false);
ButterKnife.bind(this, mRootView);
mContainer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("Test", "Clicked!");
}
});
}
Thanks for your support.
One thing to consider would be moving your OnClickListener to the parent LinearLayout you're setting as clickable and seeing if that helps.
Another thing is adding android:focusableInTouchMode="true" to the view you're attaching your OnClickListener to.
Other than that, you might want to share the code for registering the OnClickListener so we can investigate other possible errors.
If I understand correctly you want to click on the image view insideMyPageFragment.xml. This is simple but you need to give ID to the ImageView and refer it in your onCreateView method like you do for LinearLayout and then use onClickListener on that image.
So with recent conversation it seems that in linear layout you need to remove line clickable="false"
Basically that has blocked all the clicks on its children, thus that linear layout as well as the imageview clicks are not working for you. See this code I removed that line. Hope this works
Follow this code.
MyPageFragment.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:duplicateParentState="true"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="240dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:focusableInTouchMode="true"
android:id="#+id/container_linear"
android:gravity="center"
android:orientation="vertical">
<--you need to give ID to the view to be able to
perform events on them specifically.-->
<ImageView
android:id="#+id/my_awesome_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop" />
</LinearLayout>
Now in your MyFragment.class
#BindView(R.id.container_linear)
LinearLayout mContainer;
//declare with butterknife
#BindView(R.id.my_awesome_image)
ImageView myAwesomeImage;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View mRootView = inflater.inflate(R.layout.my_layout, container, false);
ButterKnife.bind(this, mRootView);
//you set click listener previously on entire linear layout instead of imageview
//that's why it was not reflecting on imageview click.
myAwesomeImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG , "Awesome Imageview clicked!");
}
});
}
I solved this issue using the following chunk of code:
#Override
public void onViewCreated(View view, Bundle savedInstanceState){
view.setOnClickListener(new OnClickListener(){
public void onClick(View v){
/* Do as you please here. */
}
});
}
The reference for this answer can be viewed here: How to detect click on ImageView in ViewPager's PagerAdapter (android)?
I am working on android application in which i am using ViewGroup to show my footer in my list view. Now i want to make an listener event for that view group, so user can press that footer. My code to make that footer and view group is given below along with the xml.
ViewGroup footer = (ViewGroup) getLayoutInflater().inflate(R.layout.footer_view, mListView, false);
View header = getLayoutInflater().inflate(R.layout.footer_view, null);
Button headerButton = (Button)header.findViewById(R.id.footerRefreshBtn);
mListView.addFooterView(footer);
headerButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "I am clicked", Toast.LENGTH_LONG).show();
}
});
// It is not showing toast message on click.
XML for footer:
<?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:clickable="true"
android:orientation="vertical" >
<Button
android:id="#+id/footerRefreshBtn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:layout_gravity="center_horizontal"
android:text="Refresh Button"
android:textColor="#color/white"
android:background="#color/gray" />
</LinearLayout>
I couldn't find out how to setOnClickListener to a footer, but I found a different solution. I think you could use this, just find the footerRefreshBtn and set Button's OnClickListener only before or after you add footer view. Both ways are working.
LayoutInflater inflater = getLayoutInflater();
ViewGroup footer = (ViewGroup) inflater.inflate(R.layout.footer, mListView, false);
mListView.addFooterView(footer, null, false);
mListView.setAdapter(mAdapter);
Button footerRefreshBtn = (Button) footer.findViewById(R.id.footerRefreshBtn);
footerRefreshBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "I am clicked", Toast.LENGTH_LONG).show();
}
});
This way, you are only assigning the Button's onClick event.
Nevertheless if you still want to set an onClickListener to a whole footer, you can get footer's layout and set an onClickListener to this layout using the method I mentioned above.
So I am using a custom ArrayAdapter implementation so that I have access to the toggle button inside my listview elements.
Each listview has a textview and a toggle button. I had to use a custom ArrayAdapter attached to the listview so that I could get the correct toggle button attached to the position of the listview that was clicked. Yet, each time I inflate the layout to get the view, the textview in the listview is disappearing. The values are still there, but the textview isnt. However the toggle buttons show up fine. This is the code used to inflate the layout and get the view:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
v = inflater.inflate(R.layout.activity_alarm_item, parent, false);
}
ToggleButton toggle = (ToggleButton) v.findViewById(R.id.alarm_status);
toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
Log.d("ENABLE ALARM", Integer.toString(position));
enableAlarm(position);
} else {
disableAlarm(position);
}
}
});
return v;
}
Does something look wrong with the two lines that inflate the layout?
The layout is fine. I reverted back to the original adapter and the textview text came back up.
However, Here is the activity layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp" >
<TextView
android:id="#+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:textIsSelectable="false"
android:textSize="20sp"
android:paddingLeft="5dp" />
<ToggleButton
android:id="#+id/alarm_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:clickable="true"
android:onClick="enableAlarm"
android:background="?android:attr/selectableItemBackground"
android:focusable="false" />
<TextView
android:layout_width="1px"
android:layout_height="fill_parent"
android:layout_toLeftOf="#id/alarm_status"
android:layout_centerVertical="true"
android:background="?android:attr/dividerVertical" />
</RelativeLayout>
Where you are setting the text to TextView ? TextView seems to be empty. That's why it is not displaying i guess.
Either set the text to TextView in Xml file itself
android:text ="text"
or else inside getView function
TextView textView = (TextView) v.findViewById(R.id.time);
textView.setText("Text");
Too long to write in a comment, I try it as an answer. I am not sure you are getting the context correctly. Personally in a custom adapter I declare the layout inflater as follow :
private LayoutInflater mInflater = (LayoutInflater)
getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
then I use the inflater in the getView() as follow
v = mInflater.inflate(R.layout.activity_alarm_item, parent, false);
Tell me if it solves your problem orelse I remove my answer.
I am trying to achieve something like this.
The Expandable List consists of the names of certain categories and when a parent is clicked, it shows the list of all the children in that category.
Now, suppose I want dynamically add a child to any category ?
How do I do that ?
Do I keep a button with every parent in the list clicking on which would add a new child under it ?
But looking around in different forums, I came to realize that it is not really easy to set a button click handler inside every parent. But if that is the only way, can anyone give me some sample code please ?
I found this thread but wasn't able to implement it in my code.
Android Row becomes Unclickable with Button
Adding a button to the group view shouldn't be that difficult.
I believe the below should work (although I don't have a project using an array backed ExpandableListView to test on).
I don't know your group row layout, so I'll make one up here for reference purposes.
group_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#android:id/text1"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center_vertical"
android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Button
android:id="#+id/addbutton"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="Add"
android:textSize="12dp" />
</LinearLayout>
Then in your getGroupView method from your adapter:
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
if (convertView == null) {
View convertView = View.inflate(getApplicationContext(), R.layout.group_layout, null);
Button addButton = (Button)convertView.findViewById(R.id.addButton);
addButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
// your code to add to the child list
}
});
}
TextView textView = (TextView)convertView.findViewById(R.id.text1);
textView.setText(getGroup(groupPosition).toString());
return convertView;
}
I'm having a weird problem, in my rather complex view layout. (I will try to simplify it a bit in my explanation)
Basically I have a ListView, where each item consists of a TextView and an ImageButton. I am able to either click the list item (on the textview), or the button (I set the ImageButton to non-focusable, otherwise it wouldn't work)
Now it seems to work fine, until I open another window and return to the listview.
From that point on, I can click the ImageButton without anything happening (not even the background changes during the click). But when I click on the TextView again, all the click events from the ImageButton are dispatched at once.
Why is that?
EDIT:
The List Item:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="0px"
android:minHeight="40dp"
android:orientation="horizontal"
android:paddingLeft="2px"
android:paddingRight="2px"
>
<TextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Text"
android:textSize="19dp"
android:paddingTop="4px"
android:paddingBottom="4px"
android:layout_gravity="center_vertical"/>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/open_subtree_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="0px"
android:orientation="horizontal"
android:padding="0px">
<View
android:layout_width="1px"
android:layout_height="match_parent"
android:background="#drawable/separator_line" />
<com.treeviewer.leveldisplay.DontPressWithParentImageButton
android:id="#+id/btn_right"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:background="#drawable/list_selector_background"
android:focusable="false"
android:focusableInTouchMode="false"
android:padding="10dp"
android:src="#drawable/arrow_right" />
</LinearLayout>
</LinearLayout>
That's how it is inflated:
[...]
LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mView = inflater.inflate(R.layout.tree_row, null, false);
TextView textView = (TextView)mView.findViewById(R.id.text1);
LinearLayout nextNodeButtonContainer = (LinearLayout)mView.findViewById(R.id.open_subtree_layout);
if(childCount >= 0) {
titleBuilder.append(" (" + childCount + ")");
nextNodeButtonContainer.setVisibility(View.VISIBLE);
View button = nextNodeButtonContainer.findViewById(R.id.btn_right);
button.setFocusable(false);
button.setFocusableInTouchMode(false);
//button.setClickable(true);
button.setOnClickListener(clickListener);
button.setTag(tagValue);
} else {
nextNodeButtonContainer.setVisibility(View.GONE);
}
textView.setText(titleBuilder);
Let me know, if you need more code.
Ok, I finally solved this problem.
Unfortunately, in my question I didn't provide the necessary information to solve it, as the problem was somewhere I didn't expect it:
I have a ListAdapter where the getView method looks like this:
public View getView(int position, View convertView, ViewGroup parent) {
return mNodes.get(position).getView(mNodeArrowClickListener, position);
}
And the getView method of the nodes (TreeLevelElements) looked like:
public class TreeLevelElement {
private final Context mContext;
private View mView = null;
//[...] other methods
View getView(OnClickListener clickListener, final int tagValue) {
if(mView == null) {
//[...] produce a new View from XML
}
return mView;
}
}
The problem was, that I stored the Views in my elements, so I guess that conflicted somehow with android strategy to reuse old views for new items.
I don't know what exactly happened, but now that I removed mView and create a new one every time, it works.
I will also change it to reuse the convertView instead.