I have a button that is a type Button that is gonna be clicked. When this is clicked, It is changing color to green.
When I click the button it changes color to green, but when I click it again, it should go back to the standard color.
I have 2 drawable files with names checked_list and not_checked_list.
These two are working good.
But when I click the button, the click has happened. And I can't click it again for some reason.
I have a Button field with a public void sendMessage method that is hooked to the buttons onClick. Is it better to just set an onClickEvent for the button in the code instead.
Here is the code I have so far.
int checked = 0;
Button gotIt;
gotIt = (Button)findViewById(R.id.got_it);
switch(checked) {
case 0:
gotIt.setBackgroundResource(R.drawable.checked_list);
checked = 1;
break;
case 1:
gotIt.setBackgroundResource(R.drawable.not_checked_list);
checked = 0;
break;
}
So here I want it to change between these two colors when I click it.
Any suggestions?
If all of the code you posted is inside your onClick method, then checked int is always 0 and will never be 1 because it is set in the first line of the method. Move your checked int outside of this method and it should work.
Setting click listener dynamically will have same result as setting in XML layout.
int checked = 0;
Button gotIt;
void sendMessage(View v) {
gotIt = (Button)findViewById(R.id.got_it);
switch(checked) {
case 0:
gotIt.setBackgroundResource(R.drawable.checked_list);
checked = 1;
break;
case 1:
gotIt.setBackgroundResource(R.drawable.not_checked_list);
checked = 0;
break;
}
}
You have to keep track of the last value for checked. Right now you are resetting it every time to 0 because it is a local field in your method call. Make checked as a class field and it will work as expected.
You can try this method
//global variables
boolean isChecked = true;
Button gotIt;
//put this in onCreate()
gotIt = (Button)findViewById(R.id.got_it);
gotIt.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if(isChecked == true){
gotIt.setBackgroundResource(R.drawable.checked_list);
isChecked = false;
}else{
gotIt.setBackgroundResource(R.drawable.not_checked_list);
isChecked = true;
}
}
});
Related
So I am facing a weird bug I cannot explain - I cannot even reproduce it sometimes.
Basic context:
I have an application, which lists objects. Every object has a name and a point value. For every object, the addCustomSpinner function creates a "ticket" (a custom view, kind-of-spinner) and shows them in a scrollview so the user can select the one needed. There are four different 'containers' for four different kind of objects - so the layout can be populated with four kind of "ticket" package.
The data for the objects are collected from a database. The addCustomSpinner is called with a for cycle for every object in the database, and - Important - before the for method, the Layout it populates with the tickets is cleared (removeAllViews).
Inside addCustomSpinner, everything is created as "new" - like the button in question.
addCustomSpinner creates this button and adds a new onClickListener. Inside onClickListener, a new boolean is created - this is used to show a different animation when the button is clicked again. On first click (boolean = true), the arrow turns 180 degrees and faces upwards, on second click (boolean = false) the arrow turns 180 degrees and faces downwards. Works like a charm, until...
The bug I am facing:
Sometimes - as I already mentioned, not every time - if I click the button for one "ticket", then leave it 'opened' and click on an another one, and leave it 'opened' also, THEN I choose to populate the layout with a different kind of "ticket" package - The arrow faces upwards by default on every ticket in every package! Sometimes - again, just sometimes - with the same pattern I can turn it back, but it happens just "by accident".
I don't understand how the animation and state of the buttons can be connected, if every created ticket is new, every button is new, every onClickListener is new, and every boolean inside onClickListener is new. And if these are connected somehow, then why can that be that every behavior is "unique" for the buttons, nothing else shows any connection - even this is just a "sometimes" bug, a pretty rare one.
Can anybody help me why this happens?
What I tried:
Well, tried to trace the issue - but since it happens just by accident, I have no clue, I just searched if I can do anything else than the boolean to add different animation for the clicks. Sadly using ObjectAnimator is not a good solution for me - not the same result at least, since my animated arrow not only rotates, but it also changes its color. Shapeshifter seemed like a good idea to create animations easily, but now as I see it, maybe a simple rotation will be my ultimate solution.
Here's the code for the button:
customButton.setOnClickListener(new View.OnClickListener() {
boolean isCustomButtonClicked = true;
#Override
public void onClick(View v) {
if (isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue_back);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(View.VISIBLE);
isCustomButtonClicked = false;
} else if (!isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(GONE);
isCustomButtonClicked = true;
}
}
});
EDIT:
The full addCustomSpinner():
private void addCustomSpinner(Routes mRouteItemToAdd, String placeName) {
//creating a new View for my custom layout created in xml
View customRoutesView = new View(this);
LinearLayout.LayoutParams customViewParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
customRoutesView.setLayoutParams(customViewParams);
customRoutesView = LayoutInflater.from(this).inflate(
R.layout.custom_view_layout, routeLayout, false
);
//Setting up the views inside the custom view
ImageView imageViewDiffImage = customRoutesView.findViewById(R.id.routeDiffImageView);
TextView textViewRouteName = customRoutesView.findViewById(R.id.routeNameTextView);
TextView textViewRouteDiff = customRoutesView.findViewById(R.id.routeDiffTextView);
ImageButton customButton = customRoutesView.findViewById(R.id.customButton);
RadioButton climberNameOne = customRoutesView.findViewById(R.id.climberNameOne);
RadioButton climberNameTwo = customRoutesView.findViewById(R.id.climberNameTwo);
Button climbedItButton = customRoutesView.findViewById(R.id.climbed_it_button);
RadioGroup climberNameRadioGroup = customRoutesView.findViewById(R.id.climberNameRadioGroup);
RadioGroup climbingStyleRadioGroup = customRoutesView.findViewById(R.id.styleNameRadioGroup);
RelativeLayout routeWhoClimbed = customRoutesView.findViewById(R.id.routeWhoClimbedRelativeLayout);
imageViewDiffImage.setImageResource(R.mipmap.muscle);
textViewRouteName.setText(mRouteItemToAdd.name);
textViewRouteDiff.setText("Difficulty: " + (int) mRouteItemToAdd.difficulty);
climberNameOne.setText(climberName1);
climberNameTwo.setText(climberName2);
routeWhoClimbed.setVisibility(GONE);
//Here comes the button with the animated image
customButton.setOnClickListener(new View.OnClickListener() {
boolean isCustomButtonClicked = true;
#Override
public void onClick(View v) {
if (isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue_back);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(View.VISIBLE);
isCustomButtonClicked = false;
} else if (!isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(GONE);
isCustomButtonClicked = true;
}
}
});
//Button, works like an 'OK' or something, and I have no
//problem with this
climbedItButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int checkedNameButton = climberNameRadioGroup.getCheckedRadioButtonId();
int checkedStyleButton = climbingStyleRadioGroup.getCheckedRadioButtonId();
RadioButton checkedNameRadioButton = (RadioButton) findViewById(checkedNameButton);
RadioButton checkedStyleRadioButton = (RadioButton) findViewById(checkedStyleButton);
String checkedName = (String) checkedNameRadioButton.getText();
String checkedStyle = (String) checkedStyleRadioButton.getText();
addClimbToDatabase(user.getUid(), checkedName, mRouteItemToAdd, placeName, checkedStyle);
}
});
//And finally, I add this new "ticket" with the custom view to the layout i want to show it. Again, this also works like a charm, no problem here.
routeLayout.addView(customRoutesView);
}
Ultimately, I did not manage to understand the problem throughly, but I was able to eliminate it.
So during my fixing tries I narrowed down the problem to the animated drawable state - credit to #avalerio for his pro tip, but the answer wasn't addig an id to the button. I think somehow and sometime, the state of the first animation (turning the arrow 180 degrees) stuck in the end position - causing the other views using this animatedDrawable showing it in end position on start.
.reset() did not help, since it resets the animatedVectorDrawable object, not the animation xml drawable state. My solution is a kind of workaround, but it is working: when the custom-view 'ticket' is created with the animated-drawable-imagebutton, I set the imageResource of the button to a not-animated xml drawable - this drawable is basically the start position of my animated-drawable. This way, when the 'tickets' are generated, the imagebutton is 'hardcoded' in the start position.
Not elegant, but works. BUT(!) I would really appreciate if someone could explain to me how this weird behavior is possible - just sometimes, randomly, with no pattern I can reproduce intentionally.
If I click a button 1 time, so it should to show number "1" in a textview. If I click again, so its should to show "2"...
#Override
public void onClick(View p1){
int id = p1.getId();
double x = 0;
//button clicked
if(id == R.id.button_contar){
x++; /*its only shows "1". When I click again, shows "1" again*/
this.mViewHolder.contados.setText(String.format("%.0f", x));
}
}
One possible approach is to initially set 0 in the textview, and with every button click you first fetch the current value in textView and then increment the value and set the new Value
int id = p1.getId();
//button clicked
if(id == R.id.button_contar){
int current = Integer.parseInt(this.mViewHolder.contados.getText().toString());
current++;
this.mViewHolder.contados.setText(String.format("%.0f", current));
}
I don't have any editor right now, so there might be some syntax errors with the above code. It will give you a rough idea on how you should solve your issue
So I have a button, and this button switches the cell of a listview with the cell above, and vise versa for ANOTHER button which is for down (this one is for up... It doesn't matter which, I just decided to talk about this one). The whole button and list view thing is working, but my problem is when I press the up button, and then decide to press it again, it just acts as a down button. The reason for this is because it's still stuck on the same item/position of the list view, and I need to figure out a way to Override the position of the onItemClick in the code??
```
upButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//upButton onClick
Integer myTeam = position; //7 -159
Integer otherTeam = position - 1; //6 - 1678
Map<Integer, String> onClickMap = sortByValue(Constants.picklistMap);
String extraValue;
Log.e("myposition", myTeam.toString());
Log.e("otherposition", otherTeam.toString());
extraValue = onClickMap.get(myTeam); //159
String team = onClickMap.get(otherTeam);
Constants.picklistMap.put(myTeam, onClickMap.get(otherTeam));
Constants.picklistMap.put(otherTeam, extraValue); //6
Log.e("Position: ",Constants.picklistMap.get(position));
Log.e("Position - 1: ",Constants.picklistMap.get(position - 1));
if(myTeam != 0) {
dref.child("picklist").child(myTeam.toString()).setValue(Integer.parseInt(Constants.picklistMap.get(myTeam)));
dref.child("picklist").child(otherTeam.toString()).setValue(Integer.parseInt(Constants.picklistMap.get(otherTeam)));
} else {
Toast.makeText(getActivity(), "Nice try.
If you try it again, the app is going to crash as punishment ... (:",
Toast.LENGTH_LONG).show();
}
}
});
```
By overriding the position, I just mean how
position =+ 1
would make position = position + 1 in python, and I want to do the same thing in Java. The problem is I know that can't be done using the snippet of code I just used to increment the value of position!
Please help!
The reason I can't use position = position + 1 is because on the onItemClick, int position is defined, and then the onClick is created for the buttons, so I need position to be final for me to use it in the onClick, and if I got rid of final, i wouldn't be able to use it in the onClick as it can't be accessed from within an inner class when it's not final
Define which position you want to change, and use this method to update position. You can use this method in onClickListener. This should work.
private int position = 0;
private void up(ArrayList<Integer> arr){
if (position < 1 || position >= arr.size()) return;
int temp = arr.get(position - 1);
arr.set(position - 1, arr.get(position));
arr.set(position, temp);
position --;
}
when I run my app it will continuously be stuck in a while loop. It should leave the while loop when a button is pressed, however even after pressing a button it continues to loop.
View.OnClickListener listener11 = new View.OnClickListener() {
#Override
public void onClick(View view) {
temp1 = button[0];
temp3 = button[0].getBackground();
state++;
}
};
while(state == 0) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
button[0].setOnClickListener(listener11);
}
variable:
state is an int temp1 is a button temp3 is a Drawable
the delay is there because I actually have 20 buttons and I have the setOnClickListeners for all the buttons inside that while loop so I think it causes it to crash without the delay. Another question would be is it possible to have the setOnClickListeners outside the while loop but still be able to check for button clicks inside the loop?
The problem is you are pressing the button while the thread is in a sleeping state causing the event to not be triggered and therefor the state to never change.
You should remove the while loop and just set all the listeners in a for loop:
for(int i = 0; i< button.length; i++) {
button[0].setTag(i);
button[0].setOnClickListener(listener11);
}
And then change your listener to be something like:
private boolean firstClick = true;
View.OnClickListener listener11 = new View.OnClickListener() {
#Override
public void onClick(View view) {
if(firstClick) {
firstClick = false;
temp1 = button[(int)view.getTag()];
} else {
temp2 = button[(int)view.getTag()];
}
}
};
I'm not sure exactly what the code is supposed to be doing because I have no idea of the context, but I think think you could remove the while loop altogether:
// initialize the listener
View.OnClickListener listener11 = new View.OnClickListener() {
#Override
public void onClick(View view) {
// add code that runs when button is clicked here
}
};
// now that we have the listener all set up we add it to the button, at which point it just keeps listening for you, no need to put the thread to sleep
button[0].setOnClickListener(listener11);
UPDATE:
So because you want to see if the second value matches the first value you could use a helper method:
private String firstValue = "";
public boolean isMatch(String mostRecentValue) {
boolean match = false;
if (firstValue.isEmpty()) {
firstValue = mostRecentValue;
} else {
match = firstValue.equals(mostRecentValue);
firstValue = "";
}
return match;
}
This method takes a value and if it is the first click the value is saved, if it is the second click it compares it with the first click and then resets the method. A boolean is returned false for no match, and true for a match. Call this method from within the onClick() method and pass in the buttons value. I've used String as an example value but you could use any object type.
I think you might be misunderstanding what setOnClickListener is doing. It's not handling the click, it is setting up the click handler. The line button[0].setOnClickListener(listener11); would be part of your activity initialisation and then not called again.
The reason you get stuck is because the main thread is busy in the while loop and isn't given an opportunity to process click events. Click events are handled on the main thread but only when it's not already busy doing something. In this case, it's forever busy in the while loop. For example, if the main thread was processing a method that would take 10 seconds to complete and you tap on a button 3 seconds into it, the button press wouldn't be handled for another 7 seconds. At which point, the previously set listener11 would be executed.
What you seem to be trying to achieve is already handled by the Looper. You need to be thinking in terms of event handling. So in other words, all your logic needs to go in listener11 or something similar.
Java Android question
I have x, say 5, buttons in a row.
Each button has a different number value displayed on the button.
Button one is active, the rest are not- not clickable. They are greyed out.
To show Button 1 is active it fades up and down.
Once clicked the button pops up a message. The user Ok's that, this activates Button 2, and deactivates Button 1.
Then it happens through all buttons, one by one. The final button doesn't produce the pop up message.
My question...
I want to create a method that sets the first button as current and then once clicked sets the next as current, and so on.
Can anyone tell me how to do this? I don't need to know how to fade buttons etc, its literally how to set button as current, and within that method the user click sets the next button as current.
Many thanks in advance.
EDIT
OK, I've had a go...its not working, but it seems so close...
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_workout_one);
int[] buttonIds = new int[] {R.id.button_1,R.id.button_2,R.id.button_3,R.id.button_4,R.id.button_5};
setButton(buttonIds);
}
private void setButton(int[] buttId){
int isCurrent = 0;
while(isCurrent < 5) {
Button currentButton = (Button) findViewById(buttId[isCurrent]);
//TODO Make current button pulse
currentButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
v.clearAnimation();
v.setBackgroundColor(0xFF00FF00);
v.setFocusable(false);
v.setFocusableInTouchMode(false);
v.setClickable(false);
setTimer();
isCurrent++;
}
});
I know that the problem is the isCurrent++ is not accessible outside the onClick method. How do I right this? Am I close or is this a major funk up and do I have to rethink?
Just use a global variable which track the current button, and check this variable to identify the current active button for determining the action in onClickListener. To fade out a button try this code snippet
button.setClickable(false);
button.setBackgroundColor(Color.parseColor("#808080"));
You need something like this:
private int activeButton = 1;
private void buttonClickHandler(){
switch(activeButton++){
case : 1
button1.setEnabled(true):
// show popup, hide/animate for button 1
break;
case : 2
button2.setEnabled(true);
// same for button 2
case : 3
// same for button 3
case : 4
// same for button 4
}