Adding button in runtime using button onclick event - java

I'm making a game in where the platform will add new button in each level the user has cleared. but I cant add new xml tag in the project on runtime. I'm a little lost of what to use or how to implement.
run = (Button)findViewById(R.id.btnRunChallengeMode);
run.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent newForm = new Intent(Form2.this,Form2.class);
buttonPanel = (LinearLayout)findViewById(R.id.LinearButtonPanel);
Button newButton = new Button(null);
newButton.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
newButton.setId(a);
newButton.setText("Button " + a);
buttonPanel.addView(newButton);
a++;
startActivity(newForm);
}
});
below is the xml code
<HorizontalScrollView
android:id="#+id/buttonPanelChallengeMode"
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_below="#+id/IDE"
android:layout_marginBottom="3dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="#color/colorPrimary"
app:layout_constraintBottom_toBottomOf="parent"
tools:layout_editor_absoluteX="8dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/LinearButtonPanel">
</LinearLayout>
</HorizontalScrollView>

This is because after adding the button to the layout you are starting the new Activity no matter it's the same activity. Whenever activity is created it will always use the initial xml format. I think you are under the impression that adding new button will persist and becomes a part of XML. That's not true, if you want to start the new activity. Set new Button value in Bundle, then in onCreate check the existence of bundle. If exist's then add a new button.
int buttonId = -1;
protected void onCreate(Bundle b){
//set the layout related stuff first
Bundle b = getIntent().getExtras();
if(b!= null && (b.getInt(NEW_BUTTON_KEY, -1)!=-1)){
buttonPanel = (LinearLayout)findViewById(R.id.LinearButtonPanel);
for(int i = 0; i< b.getInt(NEW_BUTTON_KEY, -1); i++)
Button newButton = new Button(this);
newButton.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
newButton.setId(i);
newButton.setText("Button " + i);
buttonPanel.addView(newButton);
}
}
By the way why are you making new activity? Just add the button in the same activity, otherwise your activity stack will become massic with every level.

Button newButton = new Button(null);
You give to the context null, i suggest you to give proper context. Also you can set tag for button with newButton.setTag(value)

Your Code is not true
you create a button and add to a LinearLayout and after that you call startActivity for load an Activity. So You reset the LinearLayout and buttons clear from that.
you should :
run = (Button)findViewById(R.id.btnRunChallengeMode);
run.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent newForm = new Intent(Form2.this,Form2.class);
newForm.putExtra("a", a);
startActivity(newForm);
}
});
and in the create , get Extras :
String a = getIntent().getIntExtra("a");
now you can create the button.

Related

Error "The specified child already has a parent" after LinearLayout.addView() and then Linearlayout.removeView()

I'm working on a project where I have a parent LinearLayout with id=linear_parent created on activity_main.xml. Inside this parent layout, n numbers of LinearLayouts are created programmatically base on user input at EditText (id=no_of_views_input).
And inside the each of these Linearlayouts, there are more child views (imageView, edit, button) created programmatically.
Suppose a user enters 4 no_of_views_input, the views heirarchy would be something like,
============
linear_parent
linearLayout //position 1
imageView
edit
button
linearLayout //position 2
imageView
edit
button
linearLayout //position 3
imageView
edit
button
linearLayout //position 4
imageView
edit
button
===========
After these layouts and views are created, I want to rearrange the LinearLayouts, base on user input from child id=edit.
Suppose the user enters 1 on edit at LinearLayout position 3 , what I want is, the current LinearLayout at position 3 must be added to position 1 along with its children, and finally remove the old Linearlayout which was at position 3. (would be currently at position 4 if indexes are shifted down).
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:id="#+id/linear_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:orientation="vertical">
<!-- Views are added here programmatically -->
</LinearLayout>
<EditText
android:id="#+id/no_of_views_input"
android:layout_width="100dp"
android:layout_height="40dp"
android:hint="Number of view to add"/>
<Button
android:id="#+id/add_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add"/>
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
LinearLayout linear_parent;
Button add_button;
EditText no_of_views_input;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
linear_parent = findViewById(R.id.linear_parent);
add_button= findViewById(R.id.add_button);
no_of_views_input= findViewById(R.id.no_of_views_input);
no_of_views_input.setInputType(InputType.TYPE_CLASS_NUMBER);
add_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!no_of_views_input.getText().toString().isEmpty()) {
String no_of_views_temp = no_of_views_input.getText().toString();
int no_of_views = Integer.parseInt(no_of_views_temp);
for (int i = 0; i < no_of_views; i++) {
LinearLayout linearLayout = new LinearLayout(MainActivity.this);
LinearLayout.LayoutParams lp_ll = new LinearLayout.LayoutParams(600, 1500);
lp_ll.setMargins(0, 50, 0, 0);
linearLayout.setOrientation(LinearLayout.VERTICAL);
linearLayout.setId(View.generateViewId()); // id = 1, 2, 3, 4, ...
int linearLayoutID = linearLayout.getId();
linearLayout.setLayoutParams(lp_ll);
ImageView imageView = new ImageView(MainActivity.this);
LinearLayout.LayoutParams lp_image = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 800);
imageView.setBackgroundColor(Color.Yellow);
imageView.setLayoutParams(lp_image);
EditText edit = new EditText(MainActivity.this);
LinearLayout.LayoutParams lp_edit = new LinearLayout.LayoutParams(300, ViewGroup.LayoutParams.WRAP_CONTENT);
edit.setBackgroundColor(Color.WHITE);
edit.setInputType(InputType.TYPE_CLASS_NUMBER);
edit.setHint("move to index");
edit.setLayoutParams(lp_edit);
Button button = new Button(MainActivity.this);
LinearLayout.LayoutParams lp_button= new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
button.setBackgroundColor(Color.BLUE);
button.setText("Move");
button.setLayoutParams(lp_button);
linear_parent.addView(linearLayout);
linearLayout.addView(imageView);
linearLayout.addView(edit);
linearLayout.addView(button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String indexTarget_temp = edit.getText().toString();
int indexTarget = Integer.parseInt(indexTarget_temp );
int childCount = linear_parent.getChildCount();
int currentLinearLayoutPos = linear_parent.indexOfChild(linearLayout);
try {
linear_parent.addView(linearLayout, indexTarget - 1); //adding current linearLayout to indexTarget
//error occurs this line
linear_parent.removeView(linear_parent.getChildAt(currentLinearLayoutPos + 1)); //removing linearLayout at old index
}
catch(IllegalStateException e) {
e.printStackTrace();
}
}
});
}
}else {
Toast.makeText(MainActivity.this, "Enter index no", Toast.LENGTH_SHORT).show();
}
}
});
}
}
The error I'm getting is
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
Any help would be highly appreciated.
Try to remove the child from its parent before adding it as a subview:
try {
if (linearLayout.getParent() != null) {
// Remove child from parent
((ViewGroup) linearLayout.getParent()).removeView(linearLayout)
}
linear_parent.addView(linearLayout, indexTarget - 1);
}
catch(IllegalStateException e) {
e.printStackTrace();
}
However, consider switching to a RecyclerView.
It would simplify your code structure.

Why is ImageButton (Android - Java) not implementing onClick on actual image

I have not found a clear answer on this so I figured I would write a post to see if anybody can point me in the right direction.
Basically I am creating a Voice Notes application and I have set a 'delete' button for the locally saved files as a trash can image for an ImageButton. Seeing as users will be able to save as many audio files as they want I implemented a loop where the button is created, the ID is set via setID, and then a click listener is used based on the generated ID.
My problem is that the click listener works on the sides of the image, but not on the actual image, meaning if I click to the right or left of the ImageButton the file is deleted, however, when I actually click the trash can image in the ImageButton, nothing happens. I also have logs being registered anytime the button is clicked and they also don't work when I click the actual image, so I am sure the issue is that somehow the listener is not being used when the ImageButton is clicked. - Please remember that I said the click registers to the right and left of the image.
Here is the relevant code:
try{
for (int i = 0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isFile()) {
//Button button = new Button(getApplicationContext());
TextView fileButton = new TextView(getApplicationContext());
fileButton.setTextColor(Color.parseColor("#ffffff"));
fileButton.setBackgroundResource(R.drawable.textview_button_colors);
fileButton.setTypeface(fileButton.getTypeface(), Typeface.BOLD);
fileButton.setText((i+1)+") "+listOfFiles[i].getName());
fileButton.setId(i);
fileButton.setPadding(10,10,10,10);//LTRB
fileButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
RelativeLayout deleteButton = (RelativeLayout) inflater.inflate(R.layout.image_buttons, null);
deleteButton.setId(i+i);
Log.d(LOG_TAG, String.valueOf(deleteButton.getId()) );//WORKS AS EXPECTED
deleteButton.setGravity(Gravity.CENTER_HORIZONTAL);
TableRow horizontalButtonTableRow= new TableRow(getApplicationContext());
TableLayout.LayoutParams tableRowParams = new TableLayout.LayoutParams
(TableLayout.LayoutParams.MATCH_PARENT,TableLayout.LayoutParams.WRAP_CONTENT);
int leftMargin=0;int topMargin=15;int rightMargin=0;int bottomMargin=0;
tableRowParams.setMargins(leftMargin, topMargin, rightMargin, bottomMargin);
horizontalButtonTableRow.setLayoutParams(tableRowParams);
horizontalButtonTableRow.addView(fileButton);
horizontalButtonTableRow.addView(deleteButton);
final String fileName = saveDirectory.toString() + File.separator +
listOfFiles[i].getName();
fileButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Log.d(LOG_TAG, "should be playing audio");
MediaPlayer mediaPlayer = new MediaPlayer();
try {
Vibrator vib = (Vibrator) getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
vib.vibrate(25);
FileInputStream fis = new FileInputStream(fileName);
mediaPlayer.setDataSource(fis.getFD());
Log.d(LOG_TAG, fileName);
mediaPlayer.prepare();
} catch (Exception e) {
Log.d(LOG_TAG, String.valueOf(e));
}
mediaPlayer.start();
}
});
deleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
Vibrator vib = (Vibrator) getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
vib.vibrate(25);
File deleteFile = new File(fileName);
deleteFile.delete();
savedFileLoader();
Log.d(LOG_TAG, fileName+": WAS DELETED");
} catch (Exception e) {
Log.d(LOG_TAG, String.valueOf(e));
}
}
});
verticalButtonContainerLayout.addView(horizontalButtonTableRow);
}//END IF
}//END FOR
}catch(Exception e){
Log.d(LOG_TAG,e.toString());
}
MORE INFO(but not used in final solution): If I change my code for the inflater to work like this the imageButton is no longer added to my view. I think this happens because I am forced to remove the image button from the original relative view.
LayoutInflater inflater =
(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
RelativeLayout deleteButtonLayout = (RelativeLayout)
inflater.inflate(R.layout.image_buttons, null);
ImageButton deleteButton =
deleteButtonLayout.findViewById(R.id.imageButton);
deleteButtonLayout.removeView(deleteButton);
deleteButton.setId(i+i);
If I opt not to use removeView I get this exception:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
Here is XML for imageButton in relative layout:
UPDATE: I have corrected my code based on the approved answer provided by #John Tribe. The "fix" was to set the RelativeLayout to clickable and at the same time setting the ImageButton to not be clickable. Doing this allowed my entire inflated layout to be clickable, which is exactly what I needed for this problem seeing as there was only 1 element in my inflated RelativeLayout.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:clickable="true"
android:layout_height="match_parent">
<ImageButton
style="?android:attr/buttonBarStyle"
android:id="#+id/imageButton"
android:layout_width="30dp"
android:layout_height="30dp"
android:adjustViewBounds="true"
android:clickable="false"
android:scaleType="center"
android:background="#drawable/trash"/>
</RelativeLayout>
You used RelativeLayout , You should use Image or ImageButton,but if you really want to use RelativeLayout , then in xml add android:clickable="true".
Another approach can be by finding ImageButton and setting listener.
ImageButton deleteButton = deleteButtonLayout.findViewById(R.id.imageButton);
deleteButton.setOnClickListener( new On...);

How to add buttons below each other dynamically

For the last few days, I've been trying to figure out how to make a list of buttons that are below each other, and fill the entire width of the screen dynamically. So for example:
(I cheaply just took an pre-existing screen shot that had one button and edited it in paint.net to make it look like the buttons are stacked.)
So, essentially, I have a list of strings from R that include the button's names and I need to list them like that. I've been looking around and if I did find anything it was outdated (and didn't work)
This is what I have so far (its a little messy because it contains many attempts at making this happen)
LinearLayout layout = (LinearLayout) findViewById(R.id.mainLayout);
Field[] fields = R.raw.class.getFields();
for(int count=0; count < fields.length; count++){
String filename = fields[count].getName();
try {
Button button = new Button(this);
button.setText(filename);
button.setId(startID + 1 + count); //this variable is offscreen
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//finish later
}
});
button.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
layout.addView(button);
} catch (Exception e) {
Toast.makeText(MainActivity.this, "Exception.", Toast.LENGTH_LONG).show();
}
}
(this is in onCreate() fyi)
So, if anyone has any solutions/ideas on how I can do this, please share. I'm fairly new to creating android applications.
Java
LinearLayout layout = (LinearLayout) findViewById(R.id.layout);
String[] items = {"item 1", "item 2", "item 3", "item 4", "item 5"};
for (int i = 0; i < items.length; i++) {
Button btn = new Button(this);
btn.setText(items[i]);
btn.setId(i);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(10, 10, 10, 10);
btn.setLayoutParams(params);
layout.addView(btn);
}
Xml
<LinearLayout
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</LinearLayout>
A simple example
XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/linear"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:orientation="vertical">
</LinearLayout>
</RelativeLayout>
Java:
String[] names = { "button1", "button2", "button3", "button4" };
LinearLayout layout = (LinearLayout) findViewById(R.id.linear);
for (int i = 0; i < 4; i++) {
Button button = new Button(this);
button.setText(names[i]);
button.setId(i);
button.setBackgroundColor(Color.BLUE);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
params.setMargins(20, 0, 20, 20); // (left, top, right, bottom)
button.setLayoutParams(params);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// finish later
}
});
layout.addView(button);
You might be better off learning how to use ListViews, and using Adapters to populate the ListView with Buttons containing the data from your array.
Bear in mind that for the solution you and Sajith Sageer offered, when there are too many buttons created, the buttons will extend past the screen, making them unreachable unless you wrap the LinearLayout in a ScrollView.

How can I change color of button's background

I have many buttons in my calculator app. I am testing with only one button to start, that buttons id is "one" and should change colour when I click the blue theme button. I have tried following methods:
blueTheme = (Button) findViewById(R.id.blueTheme);
blueTheme.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
one.setBackgroundColor(Color.argb(175, 144, 202, 249));
one.setBackgroundColor(Color.parseColor(/*hex code here*/));
one.setBackgroundColor(Color.BLUE);
}
});
Nothing seems to do anything. I am trying to change the colour of the button in one activity via an option in another activity. Here's actual button one:
one = (Button) findViewById(R.id.one);
one.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
result.append("1");
}
});
xml code of one in activity_main.xml:
<Button android:id="#+id/one"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:layout_weight="1"
android:background="#CCCCCC"
android:text="1"
android:textColor="#FF6600"
android:textSize="50sp"
android:layout_marginRight="1dp"
android:layout_marginTop="1dp"
android:layout_marginBottom="1dp" />
Idea is that there will be a option in another intent where I can change colors of calculator, but testing on one button fails, can't proceed. Thank you for your time.
The problem is the click from one activity cant get through to the other activity unless you pass it over.
In the activity with the blue theme button
blueTheme.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//NOTE: Where I've put MainActivity that should actually be the name
// of whatever activity this code is nested in
Intent intent = new Intent(MainActivity.this, OtherActivity.class); //use your real class name
intent.putExtra(OtherActivity.EXTRA_COLOR, Color.BLUE);
startActivity(intent);
}
});
In your OtherActivity.class
public class OtherActivity extends Activity {
public static String EXTRA_COLOR = "EXTRA_COLOR";
public void onCreate(...) {
View one = (Button) findViewById(R.id.one);
//NOTE: if you add singleTop to this activity in the manifest
// you might need to do this on onNewIntent
Intent intent = getIntent();
if (intent.hasExtra(EXTRA_COLOR)) {
int color = intent.getIntExtra(EXTRA_COLOR, Color.WHITE);
one.setBackgroundColor(color);
}
}
}
Use this :
// If you're in an activity:
yourButton.setBackgroundColor(getResources().getColor(R.color.red));
// OR, if you're not:
yourButton.setBackgroundColor(yourButton.getContext().getResources().getColor(R.color.red));
If you want to set background color without using a pre-defined color resource, do it like so
one.setBackgroundColor(0xFFFF0000); // Red
one.setBackgroundColor(0xFF00FF00); // Green
Here, 0xFF00FF00 is equivalent to #ff00ff00 (#aarrggbb)

textview giving null pointer

I hate errors like this. I'm getting a null pointer. I know what it means. I just don't understand how i'm getting it since i know that the item it should be pointing to does exist. I'm creating a textview that will be updated by the opengl renderer. The textview provides a score. I've created the textview in XML and given it a 'id', then i reference it in my program and update it through the renderer. Icreate TextView variables globally then I initialize them in the onCreate() method. Then I created a method to set the text. Which is called inside of my renderer class.
Here is my java code
View r1;
TextView score3, score4;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//set app to full screen and keep screen on
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(Main.layout);//R.layout.gl_triallayout;
r1 = findViewById(Main.id);////R.id.gl_triallayout;
score3 = (TextView) findViewById(R.id.threeScore);
score4 = (TextView) findViewById(R.id.fourScore);
......
}
public int get3(int i){
score3.setText("Score" + String.valueOf(i));
((RelativeLayout) r1).bringChildToFront(findViewById(R.id.threeScore));
Log.i("i", String.valueOf(i));
return i;
}
XML code
<TextView
android:id="#+id/threeScore"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Score"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:textSize="30dp"
android:textColor="#ffff00"/>
Update
Main class
public void Trial(View v) {
layout = R.layout.gl_triallayout;
id = R.id.glTrialLayout;
gameType = 0;
Intent intent = new Intent(Main.this, OpenGLActivity.class);
startActivity(intent);
}
public void PlayGame(View v) {
layout = R.layout.gl_layout;
id = R.id.glLayout;
gameType = 1;
Intent intent = new Intent(Main.this, OpenGLActivity.class);
startActivity(intent);
}
I hate the idea of clutter stackoverflow with the same question so if the answer is immensely simple could you give it to me in the comments. then i could delete this.
Your
setContentView(Main.layout)
should be
setContentView(R.layout.filename)
In the above code, you should change your layout file name based on your need like R.layout.activity_main.
Same applies to,
r1 = findViewById(Main.id);////R.id.gl_triallayout;
What is r1?
If it's a button, it should be
r1 = (Button) findViewById(R.id.gl_triallayout);////R.id.gl_triallayout;
If it's a Editext,
r1 = (EditText) findViewById(R.id.gl_triallayout);////R.id.gl_triallayout
If it's a TextView,
r1 = (TextView) findViewById(R.id.gl_triallayout);////R.id.gl_triallayout
Also, In your XML layout, where's the view for score4 and r1?
I think you should start learning the basics of Android first.

Categories