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");
}
}
Related
Background
I am creating buttons dynamically in a for loop by following Pragnesh Ghota's solution of one onClick listener for every button in the format of dymmeh's individual initialization solution:
LinearLayout someLayout = (LinearLayout) findViewById(R.id.theRoom);
for (int i = 0; i < neededButtons.length; i++){
neededButtons[i] = new Button(this);
neededButtons[i].setText(names[i]);
neededButtons[i].setOnClickListener(this);
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
}
In addition, I am making one onClick listener by implementing View.OnClickListener in the actvity class. My class is defined as such:
public class RecallActivity extends AppCompatActivity implements View.OnClickListener{
...
}
I have followed the other steps of Pragnesh Ghota's solution with success. However...
Problem
The fourth step of Pragnesh Ghota's solution mentions the use of a case statement to check if any of the buttons have been clicked. This works when the amount of buttons is known. However, since I am following the format laid out in dymmeh's solution, I do not know how many buttons I am checking until execution time.
Question
How do I do a control flow statement within an overrided onClickMethod for a dynamic amount of buttons?
Just create a new OnClickListener for each button when you're creating them.
LinearLayout someLayout = (LinearLayout) findViewById(R.id.theRoom);
for (int i = 0; i < neededButtons.length; i++){
neededButtons[i] = new Button(this);
neededButtons[i].setText(names[i]);
neededButtons[i].setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// add your click listener code here
}
})
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
}
you can set a id for button .just like this:
LinearLayout someLayout = (LinearLayout) findViewById(R.id.theRoom);
for (int i = 0; i < neededButtons.length; i++){
neededButtons[i] = new Button(this);
neededButtons[i].setText(names[i]);
neededButtons[i].setId(i);
neededButtons[i].setOnClickListener(this);
...
);
}
then find view by id in OnClickListener. for example:
public class RecallActivity extends AppCompatActivity implements View.OnClickListener{
#overide
public void onClick(View view){
if(view.getId == 0){
.....
}
}
}
The simplest solution is using setTag and getTag for your buttons. You can use an object with setTag and getTag. Whenever you're creating a button, set the tag for it:
for (int i = 0; i < neededButtons.length; i++){
neededButtons[i] = new Button(this);
neededButtons[i].setText(names[i]);
neededButtons[i].setTag(names[i]);
// or you can use the index as the tag with:
// neededButtons[i].setTag(i);
neededButtons[i].setOnClickListener(this);
}
Then you do something for each button by checking the tag:
#Override
public void onClick(View v) {
doSomething(v.getTag());
}
private void doSomething(Object tag) {
// in case your tag is the index, than you can convert it to
// integer and use switch case
int index = (int) tag;
switch(index) {
case 1:
...
break;
case 2:
...
break;
...
}
}
My program asks a user to enter their name and click on a button called btn. Once btn is clicked, their name is dynamically added to a TableRow along with another dynamically created Button. It's these Buttons that I'm having an issue with. I need to somehow access them later on in the program. I created a number of IDs in my res/value folder to keep track of each one(changebtn1, changebtn2, etc..). They're all stored in an array called buttonIDs.
Let's say that the user enters the first name, a new row is created with a dynamically created button:
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tableRow = new TableRow(getApplicationContext());
Button changeButton = new Button(getApplicationContext());
changeButton.setText("Change");
changeButton.setId(buttonIDs[i]);//From res/values
tableRow.addView(changeButton);
tableLayout.addView(tableRow);
i++;
});
Now let's say they enter a second name, another Button is created and so on and so forth. How can I now set an OnClickListener to my first Button that I created, which has the ID of R.id.changeBtn1? In other words, I have all of these dynamically created buttons and am not sure how to add OnClickLsteners() to earlier ones or access them in anyway. Thank you
Or you attach the OnClickListener directly in the creation of the button or you can store the references to the buttons like this:
ArrayList<Button> buttons = new ArrayList<Button>();
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tableRow = new TableRow(getContext());
Button changeButton = new Button(getContext());
buttons.add(changeButton);
changeButton.setText("Change");
changeButton.setId(buttonIDs[i]);//From res/values
tableRow.addView(changeButton);
tableLayout.addView(tableRow);
i++;
});
for(Button button: buttons){
button.setOnClickListener(new OnClickListener()
...etc...
);
}
You won't waste a lot of memory since the buttons.add() line won't copy the button in the array but just the reference to the button. If you need a in id access to the buttons, use an HashMap, like this:
HashMap<String, Button> map = new HashMap<String, Button>();
map.put("id", new Button(getContext()));
And then access it like this:
Button button = map.get("id");
How about something like this
for(int i=0;i<buttonIDs.size();i++) {
Button currentButton = (Button) findViewById(buttonIDs[i]);
currentButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Stuff
}
});
}
I did not check the code
#filnik The first part of your answer also gave me an idea. I created an OnClickListener method outside of my OnCreate() method.
View.OnClickListener changeTeamName(final Button button) {
return new View.OnClickListener() {
public void onClick(View v) {
//Do Stuff
}
};
}
I then set an OnClickListener to EACH dynamically created Button and use the method that I created.
changeButton.setText("Change");
changeButton.setTag("ButtonOne");
changeButton.setOnClickListener(changeTeamName(changeButton));
The fact that each Button now has an OnClickListener associated with it, they can now perform whatever function I add to my method.
From this code it creates dynamic buttons accodring to a given value from another layout. I need to get the id of that and add another button (if dynamic button clicks then I need to add another button dynamically).
for (int i = 0; i < value1; i++) {
LinearLayout.LayoutParams paramsIButton = new LinearLayout.LayoutParams
((int) ViewGroup.LayoutParams.WRAP_CONTENT, (int) ViewGroup.LayoutParams.WRAP_CONTENT);
ibutton = new ImageButton(HomePage.this);
ibutton.setImageResource(R.drawable.add);
ibutton.setLayoutParams(paramsIButton);
paramsIButton.topMargin = -70;
paramsIButton.leftMargin = 370;
paramsIButton.bottomMargin = 30;
ibutton.setId(i);
ibutton.getPaddingBottom();
ibutton.setBackgroundColor(Color.WHITE);
ibutton.setAdjustViewBounds(true);
rR.addView(ibutton);
}
If I understood correctly from the additional information you provided on your comment, you need to know when a user clicked on a button. You could set an OnClickListener to your button.
// Somewhere in your activity . . .
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener(){
public void onClick(View v){
// The button is clicked! Do whatever you want.
}
});
}
// ...
// Rest of the code
// ...
Of course, you should replace R.id.button1 with your button's id.
Seems to me like you need to add an onClickListener for the dynamically added button.
Make your class implement OnClickListener and then add a listener for the dynamic button:
ibutton.setOnClickListener(this);
and add an onClick Listener within your class:
#Override
public void onClick(View v)
{
// do something with this ID
v.getId()
}
I don't know how you keep track of the bulbs and fans, I'd hope you don't do it via the UI elements alone. I'd probably do it a bit differently, creating a data structure to track the bulbs and fans and attach the specific bulb or fan object to the UI element as a tag.
I have a serie of ImageViews on my Activity. And I wanna execute a method when one of these is touched. I have the next:
public void onClick(View v) {
switch(v.getId()){
case R.id.image1:
mymethod(1,1,movimientos,(ImageView)v);
break;
case R.id.image2:
ponerficha(1,2,movimientos,(ImageView)v);
break;
case R.id.image3:
...
But the method isn't executed, The problem not is the method, because any code in the cases not work. Any idea?
First thing what you need to check if you already register onClickListener for your Images
image.setOnClickListener(this);
(This you have to use if your class implements OnClickListener interface)
Then how you declare and initialize your ImageViews, whether have own ids.
image = (ImageView) findViewById(R.id.someId)
anotherImage = (ImageView) findViewById(R.id.anotherId)
...
You can work with onClickListeners like with anonyme classes like
image.setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
// some actions
}
});
but more complex and better in the case you have many widgets to set implement OnClickListener.
public class ClassName extends Activity implements View.OnClickListener {}
First, your activity has to implement View.OnClickListener like so
public class myActivity implements View.OnClickListener {
Then you need to set your on click listener for your ImageViews. If all your ImageViews are in a linearlayout then the code would look like this
LinearLayout llImageViewHolder = (LinearLayout) findViewById(R.id.llImageViewHolder);
for (int i = 0; i < llImageViewHolder.getChildCount(); i++ {
ImageView iv = (ImageView) llImageViewHolder.getChildAt(i);
iv.setOnClickListener(this);
}
Cheers.
You need to add an onClick handler to each view you are interested in processing clicks for.
How you do it depends on how you want to process the click events. You can either use hawaii.five-0's approach and have one event handler for everything, or you can have one event handler per view item which you could add in the onCreate method of your activity:
ImageView imageView = (ImageView) findViewById(R.id.image_view);
imageView.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
// Do something
}
}
The onClick never fires! Why not? Please help me.
for(int i = 0; i < 12; i++) {
String title = "Button" + i;
Button sliderButton = new Button(this);
sliderButton.setText(title);
glideMenuTray.addView(sliderButton,100,40);
sliderButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.d("gm", "Tapped ");
}
});
}
I'm no expert at stuff like this, but it's probably something to do with garbage collection, and the OnClickListeners passing out of scope.
Though I don't think you can use the super-easy approach to onClickListeners that Dimitar mentions, you can probably use the middle approach that the section he links to discusses, even though it's not a new approach. To repeat the example code here, it's:
View.OnClickListener handler = View.OnClickListener() {
public void onClick(View v) {
switch (v.getId()) {
case R.id.myButton: // doStuff
break;
case R.id.myOtherButton: // doStuff
break;
}
}
}
findViewById(R.id.myButton).setOnClickListener(handler);
findViewById(R.id.myOtherButton).setOnClickListener(handler);
If the only thing distinguishing the buttons is their title text, well, you could use that to distinguish between them in the master onClick method.
Also, not shure, I once had a problem like that on a TextView and it was because I didnt add setClickable(true)
My code was something like
TextView text = new TextView(this);
text.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
text.setText("***");
text.setClickable(true);
text.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//My action
}
});
myViewGroup.addView(text );
Hope this helps
If you are using Donut or Eclair, you can use common click listener, registered in your Activity and hooked with your buttons in the layout XML.
For reference, look here, the category Easier click listeners.
Am I right in assuming that the following line:
glideMenuTray.addView(sliderButton,100,40);
Adds the view to the coords x:100,y:40 onto some View extending ViewGroup?
In that case you are stacking 12 buttons on top of each other, only the last Button (labeled Button11) will be visible (and clickable).
And provided that the question is 3 years old I really hope you already resolved this by now :)
set the setOnClickListener before adding the view.
for(int i = 0; i < 12; i++) {
String title = "Button" + i;
Button sliderButton = new Button(this);
sliderButton.setText(title);
sliderButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.d("gm", "Tapped ");
}
glideMenuTray.addView(sliderButton,100,40);
}