Runtime onClicklLstener android - android

Just wondering can anyone solve this problem about adding listeners to imagebuttons at runtime. I'm presuming it has got something to do with the "this" parameter passed to setOnClickListener as we are already in a onClickListener.
My fragment implements onclicklistener. The onClick methods work for imagebuttons known at compile time, just not for the ones that are defined after inflating a prompt view. What seems to happen is the prompt layout seems to be recreated and added onto the back stack.
Basically the onclicklistener for mWhatsappshare,mEmail share does not react as I might expect. I put a stackoverflow error in the onclick method previously and when I clicked these imagebuttons my application did not crash. This means that the listener is in fact not registered (or at least not correctly) at
mwhatsapp.setonclicklistener(this)
By the way, I do not want to set separate listener like mWhatsapp.setonclicklistner(new View.onClickListener()){ for each imagebutton as it is too cumbersome and I want each listener to be handled in onclick().
Thank you
mOtherShare.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
removeColorFilters();
mOtherShare.setImageResource(R.drawable.other_pill_pressed);
LayoutInflater inflater = getActivity().getLayoutInflater();
View dialoglayout = inflater.inflate(R.layout.share_prompt,null);
mWhatsappShare = (ImageButton) dialoglayout.findViewById(R.id.ib_whatsapp_share);
mEmailShare = (ImageButton) dialoglayout.findViewById(R.id.ib_email_share);
mFlickrShare = (ImageButton) dialoglayout.findViewById(R.id.ib_flickr_share);
mTumblrShare = (ImageButton) dialoglayout.findViewById(R.id.ib_tumblr_share);
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(dialoglayout);
dlg = builder.show();
mWhatsappShare.setOnClickListener(this);
mEmailShare.setOnClickListener(this);
mFlickrShare.setOnClickListener(this);
mTumblrShare.setOnClickListener(this);
}
});
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.ib_whatsapp_share:
sendIntent("com.whatsapp");
break;
case R.id.ib_email_share:
sendIntent("android.email");
break;
case R.id.ib_flickr_share:
sendIntent("com.yahoo.mobile.client.android.flickr");
break;
case R.id.ib_tumblr_share:
sendIntent("com.tumblr");
break;
}
}
``

On this block of code:
mWhatsappShare.setOnClickListener(this);
mEmailShare.setOnClickListener(this);
mFlickrShare.setOnClickListener(this);
mTumblrShare.setOnClickListener(this);
this is referring to the new OnClickListener you are creating - mOtherShare.setOnClickListener(new View.OnClickListener() and NOT your fragment's OnClickListener
To use the outer onClick, change this to YourFragment.this

Related

How is it possible to know which View is clicked in a layout OnClickListener?

I have a layout which contains some views. I want to set some actions when a user clicks anywhere on the layout, so I have set an OnClickListener for the layout which works as it should. But how can I know which view was clicked?
I want to assign different actions depending on the view which was clicked; or maybe no view was clicked and it was only the layout itself.
So the problem is if I set OnClickListener for one of the views, both OnCLickListeners related to the layout and the view will get activated, but I want only the view action. Thanks in advance.
Other answers are quite abstract and some are incorrect. You can't Override onClick method for an Activity as it doesn't have one (unless of course you implement an OnClickListener).
Furthermore, if you set the listener for the layout the View argument received by the onClick method will always be the layout.
You can either create your own custom layout that intercepts the clicks and check if you clicked on a view, or you can set listeners for all the views.
A somewhat cleaner solution is using a single listener and checking if it's a view that was clicked.
private final String TAG = "MainActivity";
List<View> views = new ArrayList<View>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout rLayout = (RelativeLayout) findViewById(R.id.relativeLayout);
TextView tv1 = (TextView) findViewById(R.id.tv1);
TextView tv2 = (TextView) findViewById(R.id.tv2);
TextView tv3 = (TextView) findViewById(R.id.tv3);
views.add(tv1);
views.add(tv2);
views.add(tv3);
View.OnClickListener clickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
boolean isView = false;
for (View view : views) {
if (v.equals(view)) {
isView = true;
break;
}
}
if (isView) {
Log.e(TAG, "Click on view");
} else {
Log.e(TAG, "Click on layout");
}
}
};
tv1.setOnClickListener(clickListener);
tv2.setOnClickListener(clickListener);
tv3.setOnClickListener(clickListener);
rLayout.setOnClickListener(clickListener);
}
If you want different actions for different views, just create a listener for each of them.
For example Layout has two views View1 and View2. I assume that you have already inflated them. So you have to set OnClickListiner for each of them
Layout.setOnClickListener(this);
View1.setOnClickListener(this);
View2.setOnClickListener(this);
Then you have to override method:
public void onClick(View v)
{
switch(v.getId())
{
case R.id.id_for_layout:
// do what you want when user click layout
break;
case R.id.id_for_first_view:
// do what you want when user click first view
break;
case R.id.id_for_second_view:
// do what you want when user click second view
break;
}
}
Remember that the method OnClick have one parameter that indicates which View is clicked!
public void onClick(View v) {
switch(v.getId()) {
case R.id.btn1:
// first button
break;
case R.id.btn2:
// second button
break;
}
}
Assign the id to each of your views by android:id="#+id/v1"
then in
onClick(View v)
check for the view like
if(v == findViewById(R.id.v1))
{
// v1 specific action
}
else if(v == findViewById(R.id.v2))
{
// v2 specific action
}
Ok, it's easy.
You have to add an OnClickListener to each view (button, textView and so on), and to the whole layout as well.
In this case, the onClickListeners that will be launched if you click are the view's onClickListener and the layout's onClickListener. So no need for a whole bunch of classes. One will be enough if you try this (do actions depending on the id and don't forget the layout ;) ):
public void onClick(View v) {
switch(v.getId()) {
case R.id.layout:
layout actions here
break;
case R.id.textview:
textview actions here
break;
this onClickListener is for all of your views ;)
There is View v parameter in onClickListner(View v) method :
#Override
protected void onCreate(Bundle savedInstanceState) {
LinearLayout layout=(LinearLayout)findViewById(R.id.linearLayout);
layout.setOnclickListener(this);
}
#Override
public void onClick(View v) {
if (v.getId() == R.id.linearLayout){
//your logic
}
}
for anyone interested you can also log the currently clicked view:
getActivity()
.getWindow()
.getDecorView()
.findViewById(android.R.id.content)
.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_UP) {
Log.v("[onClick]", v.getClass().getCanonicalName());
}
return false;
});

setOnClickListener for a button inside onOptionsItemSelected causing app crash

I am invoking from a menu Item a Dialog and I have a Button inside that Dialog and trying to do something when I press the button. The part of my code for this is as followed:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.itTip:
final Dialog tipCalculator = new Dialog(this);
tipCalculator.setTitle("Tip Calculator");
tipCalculator.setContentView(R.layout.tip_layout);
totalBill = (EditText) findViewById(R.id.editTBill);
tips = (EditText) findViewById(R.id.editTTip);
calculate = (Button) findViewById(R.id.bCalcTip);
tvResult = (TextView) findViewById(R.id.tvTipResult);
calculate.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Calculate clicked", Toast.LENGTH_SHORT).show();
}
});
tipCalculator.setCancelable(true);
tipCalculator.show();
break;
}
return super.onOptionsItemSelected(item);
}
When I run my app, without the setOnClickListener, it works fine and shows the Dialog perfectly. But whenever I am trying to use the Listener, it crashes. I checked in LogCat and could actually not understand the problem clearly. Hope anyone can help me here.
I think the problem is because you attempt to find the view before you have actually shown it, this causes 'calculate' to be null when attempting to assign a onClickListener, and thus throws a null pointer exception.
To explain in a bit more detail, findViewById searches all the views currently being displayed and returns the view that matches that id. The button is contained in R.layout.tip_layout, but that view is not inflated until tipCalculator.show() is called and it won't be included in the list of views searched, so findViewById returns null.
There are a few approaches you could take to make this work, but I think the following would require the least alterations to your original code:
case R.id.itTip:
final Dialog tipCalculator = new Dialog(this);
tipCalculator.setTitle("Tip Calculator");
View contentView = View.inflate(this, R.layout.tip_layout, null);
totalBill = (EditText) contentView.findViewById(R.id.editTBill);
tips = (EditText) contentView.findViewById(R.id.editTTip);
calculate = (Button) contentView.findViewById(R.id.bCalcTip);
tvResult = (TextView) contentView.findViewById(R.id.tvTipResult);
calculate.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Calculate clicked", Toast.LENGTH_SHORT).show();
}
});
tipCalculator.setContentView(contentView);
tipCalculator.setCancelable(true);
tipCalculator.show();
break;
What we do different is inflate the view in advance (contentView) and define where to find each widget by searching that view specifically.

Dynamically populate a button value android

I have seen lots of example to which one use a if condition or a case statement to programmatically change the conditions of elements...yadda yadda. I need to change the value of a button based on what the user clicks. Below is the code that I currently have.
Button btnOpenPopup = (Button)findViewById(R.id.polarity);
btnOpenPopup = (Button) findViewById(R.id.color);
final Button finalBtnOpenPopup = btnOpenPopup;
btnOpenPopup.setOnClickListener(new Button.OnClickListener(){CONTINUES TO OTHER FUNCTIONS }
I basically need to know what button was pressed. Then dynamically populate it into findViewById() function. i.e.
btnOpenPopup = (Button) findViewById(R.id.DYNAMTICVALUEOFBUTTONUSERHASPRESSED);
This way by the time it gets to the final Button part of the code it will have the value to which the user clicked on. Code works if I only want to have one button or a page mile deep in different configuration (not ideal).
All the examples I have seen so far are after the user clicks the button (which is what I want) but they name the buttons name statically like above code shows but very much static.
Hope that all makes sense.
UPDATE:
I think I may have confused the situation. Below is the remaining code. Hopefully this will provide context. The btnOpenPopup needs to remain the same as it's used in the call to execute the command for a new window to actually popup. Hopefully this will provide a bit more context for what I'm trying to achieve.
final Button finalBtnOpenPopup = btnOpenPopup;
btnOpenPopup.setOnClickListener(new Button.OnClickListener(){
#Override
public void onClick(View arg0) {LayoutInflater layoutInflater = (LayoutInflater)getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE);
View popupView = layoutInflater.inflate(R.layout.meditationpopup, null);
//set the title of the popup
TextView titletext = (TextView) popupView.findViewById(R.id.chakratitle);
titletext.setText(activityName);
if (activityName.equals("Root"))
{
switch (arg0.getId())
{
case R.id.color:
//Rename the string so to get the value from the string xml
String stringName = activityName.toLowerCase().replaceAll(" ","")+"color";
TextView desctext = (TextView) popupView.findViewById(R.id.popupDesc);
desctext.setText(getString(getStringResource(getApplicationContext(),stringName)));
break;
case R.id.polarity:
//Rename the string so to get the value from the string xml
String polarityString = activityName.toLowerCase().replaceAll(" ","")+"polarity";
TextView polarityDesc = (TextView) popupView.findViewById(R.id.popupDesc);
//polarityDesc.setText(activityName);
polarityDesc.setText(getString(getStringResource(getApplicationContext(),polarityString)));
break;
}
}
I think
Button btnOpenPopup = (Button)findViewById(R.id.polarity);
btnOpenPopup = (Button) findViewById(R.id.color);
should be
Button btnOpenPopupFirst = (Button)findViewById(R.id.polarity);
Button btnOpenPopupSecond = (Button) findViewById(R.id.color);
you should declare different different button for diffrerent findviewbyid
also in my eclipse it is not accepting
btnOpenPopup.setOnClickListener(new Button.OnClickListener()
instead it works with
btnOpenPopup.setOnClickListener(new View.OnClickListener() {}
and you need to provide more clear view of what you want to perform
new thoughts,try doing this:
btnOpenPopupFirst.setOnClickListener(this);
btnOpenPopupSecond.setOnClickListener(this);
then option will come on both the above code lines
The method setOnClickListener(View.OnClickListener) in the type View is not applicable for the arguments (MainActivity)
choose this
let MainActivity implement OnClickListener
then this option will come
The type MainActivity must implement the inherited abstract method View.OnClickListener.onClick(View)
choose
add unimplemented method
now
#Override
public void onClick(View v)
will be created
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.polarity:
Toast.makeText(getApplicationContext(), "btnOpenPopupFirst(polarity) is pressed", Toast.LENGTH_SHORT).show();
//other code to be performed regarding this button
break;
case R.id.color:
Toast.makeText(getApplicationContext(), "btnOpenPopupSecond(color) is pressed", Toast.LENGTH_SHORT).show();
//other code to be performed regarding this button
default:
break;
}
}
And post your views after implementing this way.
int[] id={R.id.button1,R.id.button2};
Button b=(Button)findViewById(id[i]);
The onClick method in Button.OnClickListener has a View parameter... you can call getId() on that view to get the id of that button that was clicked on.
It doesn't make too much sense to me. If what you really want is this:
btnOpenPopup = (Button) findViewById(R.id.DYNAMTICVALUEOFBUTTONUSERHASPRESSED);
All you need to do is set your value in the onClick(View view) method of your OnClickListener
public void onClick(View view) {
btnOpenPopup = (Button)view;
}

setClickable() is not working on button

I want to make button unclickable using setClicable() but it's not working. I am using inflater because I need.
This is my code:
mContactList = (LinearLayout) findViewById(R.id.contactList);
LayoutInflater inflater = getLayoutInflater();
for (ListIterator<ContactModel> it = contactList.listIterator(); it.hasNext();){
ContactModel contact = it.next();
View view = inflater.inflate(R.layout.contact_unknown_list_row, null);
view.findViewById(R.id.inviteButton).setTag(contact.getEmail());
view.findViewById(R.id.inviteButton).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String address = (String) v.getTag();
sendInvatoin(address);
if(v.findViewById(R.id.inviteButton).isClickable())
v.findViewById(R.id.inviteButton).setClickable(false);
}
});
mContactList.addView(view);
}
Try using.
button.setEnabled(false);
In your case, you will do something like this:
view.findViewById(R.id.inviteButton).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String address = (String) v.getTag();
sendInvitatoins(address);
Button b = (Button)v;
b.setEnabled(false);
}
});
When using setOnClickListener, unclickable views (= v.setClickable(false)) would become clickable as mentioned in Docs.
... a callback to be invoked when this view is clicked. If this
view is not clickable, it becomes clickable.
Better to use v.setEnabled(false) if you want to set an OnClickListener to the button or any other view...
This will work in case of Imageview as well as the button.
private OnClickListener onClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
if (imageview.isEnabled()){
//I have wrapped all code inside onClick() in this if condition
//Your onClick() code will only execute if the imageview is enabled
//Now we can use setEnabled() instead of setClickable() everywhere
}}
};
Inside onCreate(), you can do setEnabled(false) which will be equivalent to setClickable(false).
We are able to use setEnabled() as tag because it's state remains unaffected on invocation of click (unlike setClickable() whose state changes).

Dynamically creating Buttons and setting onClickListener

I have problem with handling dynamically created Buttons on Android. I'm creating N buttons and I have to do the same method when button is clicked but I have to know which button is clicked.
for (int i = 0; i < NO_BUTTONS; i++){
Button btn = new Button(this);
btn.setId(2000+i);
...
btn.setOnClickListener((OnClickListener) this);
buttonList.addView(btn);
list.add(btn);
Cucurrently I'm adding ID to every button and I'm using the method below to see which button was clicked. (line btn.setId(2000+i); and btn.setOnClickListener((OnClickListener) this);). This method is also implemented in the activity.
#Override
public void onClick(View v) {
switch (v.getId()){
case 2000: selectButton(0);
break;
...
case 2007: selectButton(7);
break;
}
}
This doesn't look good to me so i'm asking is there some better way to do this? or how to send some information to onclick event? any suggestions?
You could create a method that returns an onclickListener and takes a button as a parameter. And then use that method to set the onClicklistener in the first loop you have..
Update: code could be soemthing along these lines:
View.OnClickListener getOnClickDoSomething(final Button button) {
return new View.OnClickListener() {
public void onClick(View v) {
button.setText("text now set.. ");
}
};
}
as a method in the activity and then use it in the loop like this
button.setOnClickListener(getOnClickDoSomething(button));
I got one solution for this..
use this code in onCreate
linear = (LinearLayout) findViewById(R.id.linear);
LayoutParams param = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1.0f);
Button[] btn = new Button[num_array_name.length];
for (int i = 0; i < num_array_name.length; i++) {
btn[i] = new Button(getApplicationContext());
btn[i].setText(num_array_name[i].toString());
btn[i].setTextColor(Color.parseColor("#000000"));
btn[i].setTextSize(20);
btn[i].setHeight(100);
btn[i].setLayoutParams(param);
btn[i].setPadding(15, 5, 15, 5);
linear.addView(btn[i]);
btn[i].setOnClickListener(handleOnClick(btn[i]));
}
after onCreate create one method of return type View.OnClickListener like this..
View.OnClickListener handleOnClick(final Button button) {
return new View.OnClickListener() {
public void onClick(View v) {
}
};
}
Button.OnClickListener btnclick = new Button.OnClickListener(){
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Button button = (Button)v;
Toast.makeText(getApplicationContext(), button.getText().toString(),2).show();
}
};
call this listener by btn.setOnClickListener(btnclick);
View IDs should not be used for these purposes as View Ids are generated on compilation time depending on IDs defined in xml layout files.
Just place your own IDs in the setTag() method which is available at the View level (so Buttons inherit them). This "tag" can be anything that allow you to recognize a View from others. You retrieve its value with getTag().
instead use setTag() function to distinct easily.
for(int i=0;i<4;i++) {
Button btn = new Button(this);
btn.setTag(i);
btn.setOnClickListener(new View.OnclickListener() {
#Override
public void onClick(View v) {
int i=v.getTag();
switch(i) {
case 1: btn.setText(i);
break;
case 2: btn.setText(i);
break;
case 3: btn.setText(i);
break;
case 4: btn.setText(i);
break;
default: btn.setText("Others");
}
}
}
"This doesn't look good to me" why not? doesn't it work? You could also create a static member variable holding a list of all added buttons, and then look for the clicked button in that list instead.
I don't know why you would want to create N buttons, it looks like your value of N is greater than 10 at least, if you are not trying to show them all at once (I mean fit all of them into one single screen, no scrolling) you could try to recycle the invisible buttons just like we do for list view using a list view holder. This would reduce your memory footprint and boost performance, and differentiate the buttons based either on the text you set on them or a tag or you can even hold a reference to those small number of buttons.
Is preferable not to mess up with the ids, setTag and getTag methods were designed for that purpose, it's the fast and clean way to set a bunch of button listeners on a dynamic layout
This answer may you help:
https://stackoverflow.com/a/5291891/2804001
public class MainActivity extends Activity implements View.OnClickListener
{
LinearLayout linearLayout;
Button [] button;
View.OnClickListener listener;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
linearLayout=(LinearLayout)findViewById(R.id.parent_lay);
String[] array={"U123","U124","U125"};
int length=array.length;
System.out.println("11111111111111111111111111");
button=new Button[length];
for(int i=0;i<length;i++)
{
button[i]=new Button(getApplicationContext());
button[i].setId(i);
button[i].setText("User" + i);
button[i].setOnClickListener(this);
linearLayout.addView(button[i]);
}
}
#Override
public void onClick(View view)
{
view.getId();
Button button=(Button)findViewById(view.getId());
button.setText("Changed");
}
}

Categories

Resources