I have programatically defined a set of imagebuttons in a for loop. For each button, I defined its setOnClickListener function which will put some data in the intent and then switch activity. However, it seems like no matter which button I clicked on, the extra data retrieved is set the the last value int he for loop. See code here:
public void onCreate(Bundle savedInstanceState) {
<...>
RelativeLayout rl = (RelativeLayout) findViewById(R.id.rlayout);
for (int i=1; i<=maxMapLoc; i++ ) {
mapLocation = i;
ImageButton btnMapLoc = new ImageButton(FirstActivity.this);
RelativeLayout.LayoutParams vp = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
btnMapLoc.setLayoutParams(vp);
btnMapLoc.setBackgroundColor(Color.TRANSPARENT);
btnMapLoc.requestLayout();
String imgName = "map_loc_" + mapLocation;
int id = getResources().getIdentifier(imgName,"drawable",getPackageName());
btnMapLoc.setImageResource(id);
int imgMapLoc = 2000 + mapLocation;
btnMapLoc.setId(imgMapLoc);
rl.addView(btnMapLoc, vp);
btnMapLoc.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("MapLocation", mapLocation);
startActivity(intent);
}
});
Any idea what I did wrong?
Thanks.
You could add a tag to your button with the current mapLocation value.
btnMapLoc.setTag(i);
...
// In onClick
intent.putExtra("MapLocation", v.getTag());
...
The reason why you only get the last value of mapLocation is that the code inside your onClick() is run when the user pushes a button. In other words your are querying mapLocation long after the loop built your buttons. You need to create a reference to the current mapLocation in each loop iteration, like with the tag feature.
Related
I have a LinearLayout ("ll") that is already created in xml and the app dynamically creates another LinearLayout inside of it and creates an EditText and a Button inside of that view. The button makes the whole LinearLayout destroy itself along with the EditText and Button inside it (the whole system is a player name entering activity). Anyway, I am trying to find a way to get the text from all of the EditTexts. I have tried using a for loop on "ll" and using ll.getChildAt() but I can't seem to use .getChildAt() on whatever ll.getChildAt() generates because getChildAt() generates a "View" not a "LinearLayout." I basically just need a way to search two children in, rather than just one. Also, if there is just a better way I should be doing this, let me know. I'm open to suggestions.
Here's my code if it will help:
NewGameCreate.java
public class NewGameCreate extends Activity {
int numOfPlayers = 0;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.new_game_create);
}
public void newPlayer(View view) {
numOfPlayers++;
final LinearLayout ll = findViewById(R.id.playerView);
final LinearLayout llNew = new LinearLayout(getApplicationContext());
llNew.setOrientation(LinearLayout.HORIZONTAL);
llNew.setId(numOfPlayers);
ll.addView(llNew);
EditText newName = new EditText(this);
newName.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1));
newName.setHint("Enter Player Name");
newName.setId(numOfPlayers);
newName.setWidth(0);
llNew.addView(newName);
final Button delete = new Button(this);
delete.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0));
delete.setText("Delete");
delete.setId(numOfPlayers);
delete.setWidth(0);
delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int id = delete.getId();
ll.removeViewInLayout(findViewById(id));
Drawable back = ll.getBackground();
ll.setBackgroundColor(00000000);
ll.setBackground(back);
ll.invalidate();
}
});
llNew.addView(delete);
}
public void startGame(View view){
LinearLayout ll = findViewById(R.id.playerView);
List text = new ArrayList();
for(int loop = 0; loop < ll.getChildCount(); loop++) {
//this is the code in question and where I want to get the text from
//all my EditTexts
LinearLayout inner = ll.getChildAt(loop);
}
}
}
I think I found the answer to it. You need to change a little bit of code in the startGame() method I m providing the code for startGame below.
public void startGame(View view) {
LinearLayout ll = findViewById(R.id.playerView);
List text = new ArrayList();
for (int loop = 0; loop < ll.getChildCount(); loop++) {
//this is the code in question and where I want to get the text from
//all my EditTexts
LinearLayout inner = (LinearLayout) ll.getChildAt(loop);
for (int j = 0; j < inner.getChildCount(); j++) {
if (inner.getChildAt(j) instanceof EditText) {
EditText textET = (EditText) inner.getChildAt(j);
Log.d("TAG",textET.getText().toString());
}
}
}
}
In the above code you were able to get the first child only but as you have added a linearLayout with orientation Horizontal in a parent LinearLayout with orientation Vertical, you have written code for the child of parent layout i.e playerView. I have modified the code to get the elements of the child Linear layout and Log prints all the text from the EditText.
Hope that helps!!
The scenario is, When the user clicks the button, I need to add
particular layout in known position of parent layout for the number of times button clicked.
I don't know whether it works or not. I tried this following solution which I got from other posts
Buttononclicklistenercode is,
parent = (ViewGroup) C.getParent();//c is a layout in which position i want to add view
final int index = parent.indexOfChild(C);
tobeadded=getLayoutInflater().inflate(R.layout.block_tobeadded_foremi,null);
((Button)findViewById(R.id.button88)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
addviewcount+=1;
LinearLayout addinglayout=new LinearLayout(MyActivity.this);
addinglayout.setOrientation(LinearLayout.VERTICAL);
parent.removeViewAt(index);
addinglayout.removeAllViews();
for(int i=0;i<addviewcount;i++)
addinglayout.addView(tobeadded);
parent.addView(addinglayout, index);
}
});
But I am getting java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first. In my code, before adding that layout, I have invoked the method removeViewAt() for parent.
Can anyone help me to know what is wrong in that.And Is there any other way to do this? Thanks in advance!
You are getting an IllegalStateException because you've already attached the child to the root of the layout.
parent.removeViewAt(index);
addinglayout.removeAllViews();
for(int i=0;i<addviewcount;i++)
addinglayout.addView(tobeadded);//Exception in this line
parent.addView(addinglayout, index);
Let's say addviewcount is 2.
Now in the first iteration, tobeadded is attached to addinglayout.
In the second iteration, you're again trying to attach tobeadded to addinglayout which results in an exception, since The specified child already has a parent. To solve this, You must call removeView() on the child's parent first.
All in all no child is supposed to have more than one parent. And the way you're implementing what you're trying to do is wrong. Create an array of View objects and attach them to the layout in a loop. This will solve your problem.
Here's a link where I've answered a similar question in detail few months back.
https://stackoverflow.com/a/46672959/2356570
LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT);
On Click of button try this:
addinglayout.removeAllViews();
View text = new View(context);
textNotes.setLayoutParams(lparams);
addinglayout.addView(text);
public class SampleDynamiclay extends AppCompatActivity {
Button add, replace;
LinearLayout dynamiclay;
int newid = 100;
int replaceid;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sampledynamiclay);
add = (Button) this.findViewById(R.id.add);
replace = (Button) this.findViewById(R.id.replace);
dynamiclay = (LinearLayout) this.findViewById(R.id.dynamiclay);
add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView txt = new TextView(SampleDynamiclay.this);
txt.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
newid = newid + 1;
txt.setTag(newid + "");
txt.setTextColor(getResources().getColor(R.color.black));
txt.setText("TextView " + newid);
dynamiclay.addView(txt);
}
});
replace.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
newid = newid + 1;
View removableView = dynamiclay.getChildAt(2);
dynamiclay.removeView(removableView);
TextView txt = new TextView(SampleDynamiclay.this);
txt.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
txt.setTag(newid + "");
txt.setTextColor(getResources().getColor(R.color.black));
txt.setText("TextView is replaced " + newid);
dynamiclay.addView(txt, 2);
}
});
}
}
I have created a For Loop which sets each ImageView an ID and a ClickListener. When the click is pressed, the OnClickListner either doesn't seem to be able to find the ID, or isn't called at all.
public int[] myResources = {R.id.bblock1, R.id.bblock2, R.id.bblock3, R.id.bblock4, R.id.bblock5, R.id.bblock6, R.id.bblock7, R.id.bblock8};
ImageView[] bblock = new ImageView[7];
for(int i = 0; i==myResources.length; i++) {
bblock[i]=(ImageView)layout.findViewById(myResources[i]);
bblock[i].setOnClickListener(ActivityCheck);
}
View.OnClickListener ActivityCheck = new View.OnClickListener(){
public void onClick (View v){
if( v.getId() == (R.id.bblock1)){
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://twitter.com/#!/itz_jonno"));
startActivity(browserIntent);
}
^^ The OnClickListener is not able to to find the view.
Although, WITHOUT using the array and loop the code below does work:
ImageView bblock1=(ImageView)layout.findViewById(R.id.bblock1);
bbblock1.setOnClickListener(ActivityCheck);
Any ideas why the array wont work, but the standard code will?
Change i==myResources.length into i < myResources.length.
The current loop will exit immediately unless 0 == myResources.length.
(The whole event listener thing was a nice decoy though.)
Besides problem with a loop, your Listener will work only for R.id.block1 , it will egnore events for all other views. What exactly you are trying to achieve?
for(int i = 0; i==myResources.length; i++) {
bblock[i]=(ImageView)layout.findViewById(myResources[i]);
bblock[i].setOnClickListener(
new View.OnClickListener(){
public void onClick (View v){
if( write u r checking condition here ){
start u r suitable activity here.
}
);
}
I will try to explain my problem. The code below as you can see try to add some textviews and buttons as the array get from another class.
public class Breakfast extends Activity {
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
ScrollView sv = new ScrollView(this);
LinearLayout ll = new LinearLayout(this);
sv.addView(ll);
if (extras != null) {
String food[]=extras.getStringArray("food");
String foodCateg[]=extras.getStringArray("foodCateg");
int K=0;
for (int i = 0; i < food.length/3; i++) {
TextView foodDay = new TextView(this);
foodDay.setText("Day "+ (i+1));
ll.addView(foodDay);
for (int j=K;j<K+3;j++){
Button contfood= new Button(this);
contfood.setText(food[j]);
ll.addView(contfood);
}
K=K+3;
}
this.setContentView(sv);
}
}
My question is how can I know what of this buttons are clicked on the screen?? Because in the case of what one of them are clicked (getting the text that have write before), I will do something or other thing.
ahhhhhhhhhhhhhhhhh yes I know how to do a ListActivity. But first I think in doing by hand because I don´t think how to symplify this...
Thank you for the answers of trying to build with everything a listview and then the method OnListItemClick, but I think that isn´t the solution.
I said that because when I insert the day for example (I Don´t put hear all the code...) but I do .setgravity .setSize .setbackgroundResource etc. And with the food for that day I use a diferent .setgravity and more parameters. So I think that with listview everything would have the same specifications... and that´s what I don´t like.
so... to know what button is pressed on the screen?
You could use contfood.setId(i) and work your way from there.
But what you are doing looks like you really want to create a ListActivity and use it's OnItemClickListener.
What you should do is put an id to each button "contfood". And then when you click on a button retrieve the id back to do the action you want.
Another way is to create the button and attach the method public void onClick(View view):
for (int j=K;j<K+3;j++){
Button contfood= new Button(this);
contfood.setText(food[j]);
ll.addView(contfood);
public void onClick(View view) {
Intent myIntent = new Intent(view.getContext(), xxx.class);
startActivityForResult(myIntent, 0);
}
}
and add the parameters within the method.
Firstly this has turned out to be quite a long post so please bear with me as its not too difficult but you may need to clarify something with me if i haven't explained it correctly.
So with some help the other day from guys on this forum, i managed to partially set up my 'mapClass' class, but i'm having trouble with it and its not running correctly so i would like some help if possible. I will post the code below so you can see.
What Ive got is a 'Dundrum' class which sets up the listView for an array of items.
Then ive got a 'dundrumSelector' class which I use to set up the setOnClickListener() methods on the listItems and link them to their correct views.
THIS IS MY DUNDDRUM SELECTOR CLASS....
public static final int BUTTON1 = R.id.anandaAddressButton;
public static final int BUTTON2 = R.id.bramblesCafeAddressButton;
public static final int BUTTON3 = R.id.brannigansAddressButton;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
int position = getIntent().getExtras().getInt("position");
if(position == 0){
setContentView(R.layout.ananda);
};
if(position == 1){
setContentView(R.layout.bramblescafe);
};
if(position == 2){
setContentView(R.layout.brannigans);
Button anandabutton = (Button) findViewById(R.id.anandaAddressButton);
anandabutton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Intent myIntent = new Intent(view.getContext(),MapClass.class);
myIntent.putExtra("button", BUTTON1);
startActivityForResult(myIntent,0);
}
});
Button bramblesbutton = (Button) findViewById(R.id.bramblesCafeAddressButton);
bramblesbutton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Intent myIntent = new Intent(view.getContext(),MapClass.class);
myIntent.putExtra("button", BUTTON2);
startActivityForResult(myIntent, 0);
}
});
etc etc....
Then what i did was set up static ints to represent the buttons which you can see at the top of this class, the reason for this is because in my mapClass activity I just want to have one method, because the only thing that is varying is the coordinates to each location.
ie. i dont want to have 100+ map classes essentially doing the same thing other than different coordinates into the method.
So my map class is as follows...
case DundrumSelector.BUTTON1:
handleCoordinates("53.288719","-6.241179");
break;
case DundrumSelector.BUTTON2:
handleCoordinates("53.288719","-6.241179");
break;
case DundrumSelector.BUTTON3:
handleCoordinates("53.288719","-6.241179");
break;
}
}
private void handleCoordinates(String l, String b){
mapView = (MapView) findViewById(R.id.mapView);
LinearLayout zoomLayout = (LinearLayout)findViewById(R.id.zoom);
View zoomView = mapView.getZoomControls();
zoomLayout.addView(zoomView,
new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
mapView.displayZoomControls(true);
mc = mapView.getController();
String coordinates[] = {l, b};
double lat = Double.parseDouble(coordinates[0]);
double lng = Double.parseDouble(coordinates[1]);
p = new GeoPoint(
(int) (lat*1E6),
(int) (lng*1E6));
mc.animateTo(p);
mc.setZoom(17);
mapView.invalidate();
}
Now this is where my problem is. The onClick() events don't even work from the listView to get into the correct views. I have to comment out the methods in 'DundrumSelector' before I can get into their views.
And this is what I dont understand, firstly why wont the onClick() events work, because its not even on that next view where the map is.
I know this is a very long post and it might be quite confusing so let me know if you want any clarification..
Just to recap, what i'm trying to do is just have one class that sets up the map coordinates, like what i'm trying to do in my 'mapClass'.
Please can someone help or suggest another way of doing this!
Thanks alot everyone for reading this.
The Problem ist the following:
Button bramblesbutton = (Button) findViewById(R.id.bramblesCafeAddressButton);
bramblesbutton.setOnClickListener(new View.OnClickListener() {
Here you try to set the onClickListener to a button which is only available if you're at position 2 and have called the correct setContentView() method. If you have another View as content (which does not contain your button) then
Button bramblesbutton = (Button) findViewById(R.id.bramblesCafeAddressButton);
will return null and in the next line there is a NullPointerException. So you have to only add this onClickListener if you're also using the corresponding layout.
And yes it works if you comment it out, because then you dont try to call a method on null. But on the other hand, if you comment it out, then it wont register your clicks and therefore not proceed.
To make it even clearer:
when your passing position 0, then you're setting this ContentView:
if(position == 0){
setContentView(R.layout.ananda);
};
Therefore I assume the other two Buttons will not be in this layout anada and therefore assigning a ClickListener to them will throw a NullPointerException.
To solve this issue and if you really need this 3 different layouts, I would do it that way (example for the first button):
if(position == 0){
setContentView(R.layout.ananda);
Button anandabutton = (Button) findViewById(R.id.anandaAddressButton);
anandabutton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Intent myIntent = new Intent(view.getContext(),MapClass.class);
myIntent.putExtra("button", BUTTON1);
startActivityForResult(myIntent,0);
}
});
}