My program displays a horizontally sliding row of buttons containing the text description of a work of art. When a button is clicked, ImageActivity launches to display the corresponding work of art. When I click on any of the text buttons, though, it always displays the very last painting in the Array.
I'm trying to pass an int ID to a second activity so that it will display the correct painting once it's corresponding description is clicked.
Thank you!
Here's my MainActivity:
import android.content.Intent;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
public class MainActivity extends Activity {
//CONTAINING PAINTINGS
private LinearLayout mLinearList;
private String id;
private Painting painting;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
//REFERENCE THE SCROLLABLE LAYOUT STRUCTURE IN MAIN_SCREEN.XML
mLinearList = (LinearLayout) findViewById(R.id.linearList);
//FILL THE SCROLLABLE LAYOUT STRUCTURE WITH PAINTINGS
fillTextCarousel();
}
private void fillTextCarousel() {
// POPULATE THE LINEAR LIST CAROUSEL WITH PAINTINGS AND DESCRIPTIONS
Button buttonItem;
for (int i = 0; i < RenaissanceDatabase.description.length; i++) {
//STORE THE INDIVIDUAL PAINTINGS AS BUTTONS
buttonItem = new Button(this);
painting = new Painting(RenaissanceDatabase.description[i], RenaissanceDatabase.id[i]);
//USE THE CONTENT DESCRIPTION PROPERTY TO STORE
//PAINTING DATA
buttonItem.setContentDescription(painting.getDescription());
buttonItem.setText(painting.getDescription());
//SET AN ONCLICK LISTENER FOR THE TEXT BUTTON
buttonItem.setOnClickListener(displayPainting);
//ADD THE IMAGE BUTTON TO THE SCROLLABLE LINEAR LIST
mLinearList.addView(buttonItem);
}
}
private View.OnClickListener displayPainting = new View.OnClickListener() {
public void onClick(View btn) {
// COLLECT THE IMAGE STORED FOR THE PAINTING
//String Painting_ID = Integer.toString(painting.getId());
Intent imgIntent = new Intent(getApplicationContext(), ImageActivity.class);
imgIntent.setAction(imgIntent.ACTION_SEND);
imgIntent.putExtra("image_id", painting.getId());
startActivity(imgIntent);
}
};
My ImageActivity that I am trying to pass an integer ID to:
public class ImageActivity extends Activity {
private Painting painting;
private int index;
private int[] IDs;
private String[] Desc;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
Intent objIntent = getIntent();
int ID_Val = objIntent.getIntExtra("image_id", 0);
ImageView art = (ImageView) findViewById(R.id.imageView2);
art.setImageResource(ID_Val);
}
}
And the painting database, which I'm taking taking the ID from:
public class RenaissanceDatabase {
public static String description[] = {
"Venus of Urbino\nTitan, 1538",
"St. John the Baptist\nLeonardo da Vinci, 1516",
"Protrait of Baldassare Castiglione\nRaphael, 1515",
"The Entombent of Christ\nCaravaggio, 1603",
"Coronation of the Virgin\nFra Angelico, 1435",
"Mars and Venus\n Sandro Bottcelli, 1483"};
public static int id[] = {
R.drawable.painting1, // VENUS OF URBINO
R.drawable.painting2, // ST.JOHN BAPTIST
R.drawable.painting3, // BALDASSARE
R.drawable.painting4, // ENTOMBENT OF CHRIST
R.drawable.painting5, // CORONOATION
R.drawable.painting6 // MARS AND VENUS
};
}
Set the id for every button in your for loop -
for (int i = 0; i < RenaissanceDatabase.description.length; i++) {
//STORE THE INDIVIDUAL PAINTINGS AS BUTTONS
buttonItem = new Button(this);
painting = new Painting(RenaissanceDatabase.description[i], RenaissanceDatabase.id[i]);
//USE THE CONTENT DESCRIPTION PROPERTY TO STORE
//PAINTING DATA
buttonItem.setId(painting.getId());
....
}
}
And then change your OnClickListener -
private View.OnClickListener displayPainting = new View.OnClickListener() {
public void onClick(View btn) {
....
imgIntent.putExtra("image_id", btn.getId());
startActivity(imgIntent);
}
};
The way your code is set up this makes perfect sense.
Look at the loop you're using to configure everything.
for (int i = 0; i < RenaissanceDatabase.description.length; i++) {
.....
painting = new Painting(RenaissanceDatabase.description[i], RenaissanceDatabase.id[i]);
...
}
What is the value of painting at the end of this loop? It's whatever was in the last position in the array.
Now look at your code to pass the ID:
private View.OnClickListener displayPainting = new View.OnClickListener() {
public void onClick(View btn) {
....
imgIntent.putExtra("image_id", painting.getId());
.....
}
};
The code presented never updates the "current painting" to the one which was touched. You need to figure out which painting the user has touched, and use the ID of that painting.
Another answer has a recommendation to set the buttonId to the id of the painting - this has some issues so I wouldn't personally recommend that.
Instead I would use an Adapter and ViewHolder pattern and leverage the viewholder to contain this meta data. This is a much more scalable solution.
Related
I have two inner classes named CalculatorClass and UpdatePayment in MainActivity class.
In UpdatePayment class there is a for loop and I have a array of Buttons.
I want to add listener to each button in loop. Those buttons will initialize the CalculatorClass and get value of calculations.
Demo code is:
public static class MainActivity{
private interface UpdateEditText{
void onCallback(String s);
}
private class CalculatorClass extends Dialog{
UpdateEditText updateEditText;
public CalculatorInterface(#NonNull Context context, UpdateEditText updateEditText) {
super(context);
this.updateEditText = updateEditText;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.calculator);
initialize();
}
initialize(){
.......................
s = "Some texts";
updateEditText.onCallback(s);
}
}
private class UpdatePayment extends Dialog{
private Button[] button = new Button[100];
private EditText[] editText = new EditText[100];
public CalculatorInterface(#NonNull Context context) {
super(context);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.update);
initialize();
}
initialize(){
.......................
for(int i = 0; i < MAXSize; i++){
button[i] = new Button(MainActivity.this);
editText[i] = new EditText(MainActivity.this);
//add buttons to view to layout
button[i].setOnclickListener(new View.OnClickListener(){
public void onClick(View v) {
CalculatorClass calculator = new
CalculatorClass(MainActivity.this,
new UpdateEditText() {
#Override
public void onCallback(String s) {
editText[i - 1].setText(s);
}
});
calculator.show();
}
);
}
}
}
}
Problem is the line editText[i].setText(s) work for the last editText what ever button I click, i.e, any button I click, it fills the editText[MaxSize -1]
What should I do?
How can I perform this action for all i?
Please help me, I tried a lot searching in internet, still I didn't get any solution.
Anonymous classes are very much treated like static variables in java.It's happenning because your i value after your activity is initialized is equal to 1 less than the length of the edit text array.
editText[indicies_of_button_clicke].setText(s)
How you will get the indicies of button clicked is by :
se the tag to button below this line "editText[i] = new EditText(MainActivity.this);", like this :
button[i].setTag(i)
to retreive the index of your actual button clicked inside button clicklisteners,
v.getTag()// this will give you an integer value which will be the indices of actual button clicked
//use this value to set your edit text value.
Solution:
After a whole night, I got answer, now I feel awwww, this was easy go!
I never came in this thought.
button[i].setId(i);
then call:
CalculatorClass calculator = new CalculatorClass(MainActivity.this, v.getId(),
new UpdateEditText() {
#Override
public void onUpdate(String s, int ID) {
Log.i("test", ID + "");
editText[ID].setText(s);
}
});
At the same time, #Rishabh Ritweek answered correctly.
Thanks to him.
I created some Chips and they have an X symbol on the right side.
But when I click the X (intending to dismiss or remove the Chip), nothing happens.
I tried to use the method setOnCloseIconClickListener but it did not have an effect.
I click the X icon and the color of the icon changes and a clicking sound appears, but the Chip View remains on the screen.
And I also don't know what to write in the callback method of the click listener.
for(int i = 0; i<products.length; i++) {
//the chip component requires your app theme to be Theme.MaterialComponents (or a
//descendant)
chips[i] = new Chip(this);
//ScrollView can only host one direct child
ll1.addView(chips[i]);
chips[i].setText(products[i]);
chips[i].setCloseIconVisible(true);
}
I tried this, but it said the variable i has to be final which is not possible cause i is incrementing.
chips[i].setOnCloseIconClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
chips[i].close();
}
});
I found the solution. This is the code:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private EditText et1;
private ScrollView sv1;
private LinearLayout ll1;
private Chip[] chips;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et1 = findViewById(R.id.editText);
sv1 = findViewById(R.id.scrollView);
ll1 = new LinearLayout(this);
ll1.setOrientation(LinearLayout.VERTICAL);
sv1.addView(ll1);
}
public void splitToChips(View v) {
String content = et1.getText().toString();
String[] products = content.split(";");
chips = new Chip[products.length];
for(int i = 0; i<products.length; i++) {
chips[i] = new Chip(this);
ll1.addView(chips[i]);
chips[i].setText(products[i]);
chips[i].setCloseIconVisible(true);
chips[i].setOnCloseIconClickListener(this);
}
}
#Override
public void onClick(View v) {
Chip chip = (Chip) v;
ll1.removeView(chip);
}
}
i am new to development. i am creating an android calculator app with advanced functionality.The thing is i am using text view for taking and displaying inputs/outputs. My question is, how can i take Multiple inputs in multiple Textviews.
For example i have 3 text views,when user will enter 1st input in first textview(by default) and when user press the specific button it moves automatically to next textview . In some cases i want to take 2 inputs and in some cases i want to take 3 ,
How can i achieve this
Note: I dont want to use edit text , coz all buttons of already available in my app.Using Edit text will make softkeyboard to appear, and then for hiding the softkeyboard, i need to use hiding code lines in every class
You can do something like following:
private TextView[] textViews;
private TextView tvCurrentEditing;
private Button btnNext;
private Button btnPrev;
private Button btnSetText;
private int index = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
textViews = new TextView[3];
//Initialize all your textviews like textViews[0] = findViewById(<textview-id1>);
//textViews[1] = findViewById(<textview-id2>);
//textViews[2] = findViewById(<textview-id3>);
tvCurrentEditing = textViews[index];// I am assuming this is your first
//initialzie btnSettext
btnSettext.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tvCurrentEditing.setText("<what ever you want");
}
});
//initialize next buton
btnNext.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(index < textViews.length) {
index++;
}
tvCurrentEditing = textViews[index];
}
});
//Initialize previous button
btnPrev.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(index > 0) {
index--;
}
tvCurrentEditing = textViews[index];
}
});
}
The names of the views could be different. The point is always use tvCurrentEditing whenever you want to change data of TextView. And update tvCurrentEditing whenever needed.
I'm a beginner with Android development (and Java). I've a number of ImageView in a layout (2d array of images). What I'm trying to implement is, each time when I click on an ImageView, it should set an image from an array based on some logic with current image being displayed (e.g. next image in array, with each click). I have googled and managed to do this but it looks rather long.
public class GameActivity extends AppCompatActivity {
private int [] inputTiles = {R.drawable.one, R.drawable.two, ...// more images};
Random r = new Random();
int matSize = 5;
int[][] indexMat = new int[matSize][matSize];
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
for (int i=0; i<matSize; i++) {
for (int j=0; j<matSize; j++) {
indexMat[i][j] = r.nextInt(10);
}
}
final ImageView tile00 = findViewById(R.id.tile00);
tile00.setImageResource(inputTiles[indexMat[0][0]]);
tile00.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
indexMat[0][0] = (indexMat[0][0]+1)%5;
tile00.setImageResource(inputTiles[indexMat[0][0]]);
}
});
final ImageView tile01 = findViewById(R.id.tile01);
tile01.setImageResource(inputTiles[indexMat[0][1]]);
tile01.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
indexMat[0][1] = (indexMat[0][1]+1)%5;
tile01.setImageResource(inputTiles[indexMat[0][1]]);
}
});
...// a lot more ImageViews
}
}
Say I'm displaying 5x5 grid of images. I've the available images in an array inputTiles and a 5x5 array indexMat to store the index of current image at a location i, j. Then, for each ImageView I'm listening for click and choosing another image to display from array. This is working perfectly, but I have to write "clicklisten and action" block 25 times, in this particular example. It'd be really great if there's a way to loop this so that I can have any n x n grid.
I tried looping after a bit googling, by keeping ImageView in a 5x5 array and looping over it, but the loop variables doesn't seem to go inside the setOnClickListener() function. It says I need to make i and j as final but then it becomes constants, so doesn't work. Below code is what I tried, but it doesn't work that way.
final ImageView[][] tiles = {{findViewById(R.id.tile00), findViewById(R.id.tile01), findViewById(R.id.tile02),...},
{findViewById(R.id.tile10), ...,}};
for (int i=0; i<3;i++){
for (int j=0; j<3; j++){
tiles[i][j].setImageResource(inputTiles[indexMat[i][j]]);
tiles[i][j].setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
indexMat[i][j] = //doesn't work
}
});
}
}
Any ideas?
The simplest way of doing this is to have a RecyclerView with a GridLayoutManager. Here's a nice example about how you can achieve your desired functionality in a RecyclerView.
Once you are setting these images in your RecyclerView, you can easily manage the click listener in your onBindViewHolder function, based on the position you have clicked.
I'm using two buttons with the same id in two different layouts in my app where when the first one is clicked, the app loads the 2nd layout and when the button with the same id in the 2nd layout gets clicked, it loads the first layout file. However, my issue is that this toggling happens only once and after that the button doesn't do anything. Do you have any idea on how i can call these onClickListeners whenever each button is clicked until the user leaves that activity?
CardViewActivity.java:
public class CardViewActivity extends AppCompatActivity {
private ImageView cardArtImageView;
private TextView leaderSkillDescText;
private TextView superAttackTitleText;
private TextView superAttackDescText;
private TextView passiveSkillTitleText;
private TextView passiveSkillDescText;
private TextView hpText;
private TextView attText;
private TextView defText;
private TextView costText;
private Button arrowButton;
private int selectedItemPosition;
private boolean isBtnClicked = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.cardview_refined);
// Retrieving the data sent over from MainActivity
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
if (bundle != null) {
selectedItemPosition = bundle.getInt("Card Index");
}
//Toast.makeText(this, "WIDTH: " + SCREEN_WIDTH, Toast.LENGTH_SHORT).show();
// Initializing our views
cardArtImageView = findViewById(R.id.cardArtImageView);
viewDefinitions(false);
setSelectedViewsInit();
initCardViewData(selectedItemPosition);
arrowButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
isBtnClicked = !isBtnClicked;
if (isBtnClicked) {
setContentView(R.layout.cardview_expand_details);
viewDefinitions(true);
initCardViewData(selectedItemPosition);
setSelectedViewsInit();
Log.d("BTN", "Btn Clicked 1st time");
arrowButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setContentView(R.layout.cardview_refined);
cardArtImageView = findViewById(R.id.cardArtImageView);
viewDefinitions(false);
initCardViewData(selectedItemPosition);
setSelectedViewsInit();
isBtnClicked = !isBtnClicked;
Log.d("BTN", "Btn Clicked 2nd time");
}
});
}
}
});
}
/**
* Sets the required textViews as selected to allow automatic scrolling
*/
private void setSelectedViewsInit() {
leaderSkillDescText.setSelected(true);
superAttackTitleText.setSelected(true);
superAttackDescText.setSelected(true);
if (passiveSkillTitleText != null && passiveSkillDescText != null) {
passiveSkillTitleText.setSelected(true);
passiveSkillDescText.setSelected(true);
}
}
/**
* Adds the views's definitions
*
* #param initPassiveInfo used to decide whether or not the passiveSkillDesc & ..Title != null
* so that they can be defined
*/
private void viewDefinitions(boolean initPassiveInfo) {
leaderSkillDescText = findViewById(R.id.leaderSkillDesc);
superAttackTitleText = findViewById(R.id.superAttackTitle);
superAttackDescText = findViewById(R.id.superAttackDesc);
if (initPassiveInfo) {
passiveSkillTitleText = findViewById(R.id.passiveSkillTitle);
passiveSkillDescText = findViewById(R.id.passiveSkillDesc);
} else {
Log.d("Definitions", "Passive info == null");
}
hpText = findViewById(R.id.HP);
attText = findViewById(R.id.ATT);
defText = findViewById(R.id.DEF);
costText = findViewById(R.id.COST);
arrowButton = findViewById(R.id.arrowButton);
}
/**
* Initialize the cardViewActivity's views with the data from the CardInfoDatabase.java class
*
* #param selectedItemPosition Used to initialize this activity's views if the intent was called from the MainScreen Fragment
*/
private void initCardViewData(int selectedItemPosition) {
if (cardArtImageView != null) {
cardArtImageView.setImageResource(CardInfoDatabase.cardArts[selectedItemPosition]);
}
leaderSkillDescText.setText(CardInfoDatabase.leaderSkills[selectedItemPosition]);
superAttackTitleText.setText(CardInfoDatabase.superAttacksName[selectedItemPosition]);
superAttackDescText.setText(CardInfoDatabase.superAttacksDesc[selectedItemPosition]);
if (passiveSkillTitleText != null && passiveSkillDescText != null) {
passiveSkillTitleText.setText(CardInfoDatabase.passiveSkillsName[selectedItemPosition]);
passiveSkillDescText.setText(CardInfoDatabase.passiveSkillsDesc[selectedItemPosition]);
}
hpText.setText(CardInfoDatabase.hp[selectedItemPosition].toString());
attText.setText(CardInfoDatabase.att[selectedItemPosition].toString());
defText.setText(CardInfoDatabase.def[selectedItemPosition].toString());
costText.setText(CardInfoDatabase.cost[selectedItemPosition].toString());
}
}
To avoid this issue, you need to make sure that the OnClickListener you assign to the button always sets the OnClickListener for the button in the "new" layout.
I haven't tested this, but it seems like it should work in theory. Try defining the listener as a private member of your class, then setting it in your onCreate, like arrowButton.setOnClickListener(arrowClickListener);:
private void arrowClickListener = new View.OnClickListener(){
#Override
public void onClick(View view) {
// clicked buttton -- pick layout based on button "state"
int resId = isBtnClicked ? R.layout.cardview_expand_details : R.layout.cardview_refined;
// set the contentview with the layout we determined earlier
setContentView(resId);
// If we're in the "normal" view, find the card art view and set our field to it
if (!isBtnClicked){
cardArtImageView = findViewById(R.id.cardArtImageView);
}
// do other initialization stuff
viewDefinitions(isBtnClicked);
initCardViewData(selectedItemPosition);
setSelectedViewsInit();
// set our new arrow button click listener to this listener
arrowButton.setOnClickListener(arrowClickListener);
// toggle button flag
isBtnClicked = !isBtnClicked;
}
}
Sorry if I got some of the logic wrong -- the key in this case is to set the click listener "recursively", in a manner of speaking, which ensures that a listener gets set after every click.