Button working on second click android - java

I have a button in my Fragment. Which supposed to turn into R.drawable.role_button_pressed then i press it or if my button is already pressed it supposed to turn into original R.drawable.role_button then i press it. But then i am pressing my button it need to be pressed twice to change it state.
My xml looks like this:
<Button
android:id="#+id/role"
android:layout_width="40dp"
android:layout_height="40dp"
android:gravity="center"
android:layout_marginTop="#dimen/margin_role_buttons_top"
android:layout_marginRight="#dimen/margin_role_buttons_right"
android:layout_marginBottom="#dimen/margin_role_button_bot"
android:text="#string/jungle"
android:textColor="#android:color/black"
android:layout_below="#id/divider4"
android:layout_toLeftOf="#id/role_mid_lookingfor"
android:background="#drawable/role_button" />
and on click method
boolean isPressed = true;
Button rolebutton = (Button) v.findViewById(R.id.role);
rolebutton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!isPressed){
rolebutton.setBackgroundResource(R.drawable.role_button_pressed);
isPressed=true;
}else if(isPressed==true){
rolebutton.setBackgroundResource(R.drawable.role_button);
isPressed=false;
}
}
});

You have the wrong default boolean in the first place.
I assume the starting resource is R.drawable.role_button.
Change isPressed to false and put it into your clickListener, because it's not pressed right?
And I suggest you to use a better shortcut in your if else
rolebutton.setOnClickListener(new View.OnClickListener() {
boolean isPressed = false;
public void onClick(View v) {
rolebutton.setBackgroundResource(isPressed ? R.drawable.role_button : R.drawable.role_button_pressed));
isPressed = !isPressed;
}
}

Related

Adding basic click animation to dynamic buttons

I have a simple button that looks like:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:tag="general"
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#343535"
android:orientation="vertical"
tools:context=".fragments.GeneralFragment">
<Button
android:id="#+id/hello"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center_vertical"
android:onClick="onClick"
android:text="#string/hello" />
Instead of static, these buttons should now be dynamic
Button button = (Button) layout.getChildAt(0);
for(String text : readFromSharedPreferences) {
// Set the layout
Button btn = new Button(this.getContext());
btn.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
btn.setText(text);
btn.setTag(text);
btn.setLayoutParams(button.getLayoutParams());
btn.setBackground(button.getBackground());
layout.addView(btn);
The static button has an animation when I click on it. That looks like this:
But the dynamic button has no animation. So when I click on it, nothing happens. That looks like this:
How can I add this animation to my dynamic buttons?
Update
I have figured out that my loop contains an on-touch listener. That looks like this:
btn.setOnTouchListener(new OnSwipeTouchListener(getContext()) {
// No code in here
});
If I remove that listener (even if it contains no code), the animation works great but I would like to keep it, because of my swipe function that is placed into it.
That is my whole code:
// Swiping to link
btn.setOnTouchListener(new OnSwipeTouchListener(getContext()) {
#Override
public void onSwipeLeft() {
super.onSwipeLeft();
// Alert to ask
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Delete");
builder.setMessage("Do you want to delete?");
// Delete
builder.setPositiveButton("Yes", (dialog, which) -> {
// Set the SharedPreferences as String
ArrayList<String> currentSharedPreferences = readFromSharedPreferences(getContext());
currentSharedPreferences.remove(btn.getTag().toString());
Gson gson = new Gson();
String currentSharedPreferencesAsText = gson.toJson(currentSharedPreferences);
// Update the SharedPreference k-text
SharedPreferences mPrefs = getContext().getSharedPreferences("k-texts", Context.MODE_PRIVATE);
SharedPreferences.Editor prefsEditor = mPrefs.edit();
prefsEditor.putString("k-text", currentSharedPreferencesAsText);
prefsEditor.apply();
// Start the animation
btn.animate()
.translationX(-btn.getWidth())
.alpha(0.0f)
.setDuration(300)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
btn.clearAnimation();
btn.setVisibility(View.GONE);
Snackbar.make(view, "Entry deleted.", Snackbar.LENGTH_LONG).setAction("Delete", null).show();
}
});
});
// Cancel
builder.setNegativeButton("No", (dialog, which) -> {
// Silence is golden
});
builder.show();
}
#Override
public void onClick() {
MainActivity mainActivity = new MainActivity();
Tts tts = new Tts(getContext(), _mediaPlayer, mainActivity.barTop, mainActivity.barBottom);
try {
tts.say(btn.getTag().toString());
} catch (Exception e) {
e.printStackTrace();
}
}
});
Well I could use
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
return false;
}
Then the animation will work but onClick() wouldn't work anymore.
Another update
I had a similar problem on another view. There my static button was not having a click effect. Then I have just simply added android:foreground="?attr/selectableItemBackground" and it worked! The same way I have just tried with my dynamic button. So I have added btn.setForeground(button.getForeground()); but that doesn't do anything.
Use MaterialButton instead of Button. MaterialButton is a subtype of Button that supports additional features. The Button that is in your XML layout is actually a MaterialButton if you're using a Material Components theme. The theme automatically swaps out Buttons for MaterialButtons when your XML is inflated. So, when dynamically creating buttons in your Java code, you must use MaterialButton if you want it to match the original.
Also, when using MaterialButton, never call setBackground() because this causes undefined behavior. It likely will prevent the ripple effect from occurring as well.
Alternatively, you can define your Button in its own XML file, even with the layout params it needs for LinearLayout. Then inflate the XML each time you need another button.
for(String text : readFromSharedPreferences) {
Button btn = requireContext().getLayoutInflater()
.inflate(R.layout.my_button, layout, true); // true adds it to layout
btn.setText(text);
btn.setTag(text);
}

Getting nothing while calling performClick() function - Android

I'm new to Android developing and now I'm trying to simulate click on my AutoCompleteTextView object.
I'm expecting default android's keyboard appearance with the possibility to type something at the element
Here is a simple function, where I'm trying to perform it:
private void someTestMethodName() {
AutoCompleteTextView tagSearchInput = findViewById(R.id.autoCompleteTextView);
tagSearchInput.performClick();
}
And here is .xml element defining:
<AutoCompleteTextView
android:id="#+id/autoCompleteTextView"
android:text="TextView"
android:layout_width="188dp"
android:layout_height="62dp"
android:layout_alignParentStart="true"
android:layout_marginStart="108dp"
android:layout_alignParentTop="true"
android:layout_marginTop="292dp"/>
Calling performClick on a TextView does not pop up the soft keyboard, but you can quite easily do that yourself:
private void someTestMethodName() {
AutoCompleteTextView tagSearchInput = findViewById(R.id.autoCompleteTextView);
showSoftKeyboard(tagSearchInput);
}
public void showSoftKeyboard(View view){
if(view.requestFocus()){
InputMethodManager imm =(InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(view,InputMethodManager.SHOW_IMPLICIT);
}
}
More information can be found here: https://github.com/codepath/android_guides/wiki/Working-with-the-Soft-Keyboard
i never used performClick, you cant use setOnClickListener to catch a click
tagSearchInput.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//do somthing
}
});

Handling Multiple Buttons [duplicate]

This question already has answers here:
One OnClickHandler for multiple Buttons
(6 answers)
Closed 7 years ago.
I have an activity that is a full screen of 25 buttons. I was wondering if there was a more efficent was to create listeners for them so that they change colour when clicked instead of:
Button buttonA1;
Button buttonA2;
Button buttonA3;
...
buttonA1 = (Button) findViewById(R.id.buttonA1);
buttonA2 = (Button) findViewById(R.id.buttonA2);
buttonA3 = (Button) findViewById(R.id.buttonA3);
...
and then adding a listener for each...
Is it possible to condense all this into considerably less lines of code?
In xml file, you can implement OnClickListener for button like this :
...
<Button android:id="#+id/mybutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="myMethod" />
Then, in your java file
public void myMethod(View v) {
// does something very interesting
}
You can set in your XML file the android:onClick for each button.
android:onClick="onClick"
Then in your MainActivity you can use something like.
public void onClick(View v) {
//Handle the buttons
public void onClick(View v) {
switch(v.getId())
{
case R.id.button_a_id:
// handle button A click;
break;
case R.id.button_b_id:
// handle button B click;
break;
default:
throw new RuntimeException("Unknow button ID");
}
}
Hope it helps.

Retaining focus on Edittext within OnFocusChanged Listener

I am trying to set up a system to validate user input, in this case, just checking that there is anything entered by the user.
I have a Utility class that checks that the EditText has data.
I am using an OnFocusChangeListener which then calls the method from the Utility class.
This is the code from the activity:
editText = (EditText) view.findViewById(R.id.editText);
editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
if (Utility.checkInput(editText) == false) {
Toast.makeText(getActivity(), "Enter value!",
Toast.LENGTH_SHORT).show();
// TODO....
// Retain focus - do not allow user to move on.
// This is where I am lost...
}
}
}
});
This is the code from the Utility class:
public class Utility {
public static boolean checkInput(EditText editText) {
if (editText.getText().length() != 0) {
return true;
}
return false;
}
//.../
Where I am stumped is how to retain focus if the check input returns false. I want to prevent the user from moving forward. I am sure there is a simple solution, but I have not found it.
I am also wondering if the xml ime.Options will affect this.
Thanks.
EDIT
This is my xml:
<EditText
android:imeOptions="actionDone"
android:inputType="textPersonName"
android:maxLength="24"/>
<spinner ../
<EditText
android:imeOptions="actionDone"
android:inputType="phone"
android:maxLength="12"/>
When I use:
if (!hasFocus) {
if (Utility.checkInput(name) == false) {
Toast.makeText(AddDriverUserActivity.this, "Enter value!",Toast.LENGTH_SHORT).show();
name.requestFocus();
}
}
The problem is, I am using action done (to hide the keyboard), as the user then selects from a spinner then proceeds to the next EditText. So the toast isn't showing until I touch the next edit text (phone) and the focus is then set on two edit texts:
When I reset:
android:imeOptions="actionDone"
to actionNext it shows the toast and then proceeds to the next edittext, as shown in the screen shot, both are focused.
Request focus doesn't prevent it from moving from the edittext.
Use View.requestFocus()
// Retain focus - do not allow user to move on.
editText.requestFocus();
This isn't a solution to retaining focus within the EditText to validate input, but it is an elegant way to check for user input.
I add all my EditTexts to an array and pass them to a method that loops through the array and checks each for input.
In my Utility class:
public static boolean checkAllInput(EditText[] editTexts) {
for (int i = 0; i < editTexts.length; i++) {
if (editTexts[i].getText().length() == 0) {
return false;
}
}
return true;
}
In the activity/fragment:
I add the EditTexts to an array:
final EditText[] editTexts = {arg1, arg2, arg3, arg4, .../};
Then use the function in my OnTouchListener for the button.
addBtn.setOnTouchListener(new View.OnTouchListener() {
#Override public boolean onTouch(View v, MotionEvent event) {
hideKeyboard();
disableButton(addBtn);
if (Utility.checkAllInput(editTexts) == false) {
Toast.makeText(getActivity(), "Enter all fields",
Toast.LENGTH_SHORT).show();
enableButton(addBtn);
} else {
// Do something ..
}
return false;
}
});
I thought this might be helpful for others working their way through android.
As a side note, I have been disabling my buttons, to prevent repeated touches:
Using countdown to set button enabled

onClick event is not triggering | Android

I made a very simple test application with one activity and one layout. The onClick doesn't trigger the first time it is pressed, as it should.
The activity:
package com.example.mytest;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText ed1 = (EditText) findViewById(R.id.editText1);
ed1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "1", Toast.LENGTH_LONG)
.show();
}
});
}
}
The layout:
<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" >
<EditText
android:id="#+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:ems="10" >
<requestFocus />
</EditText>
<EditText
android:id="#+id/editText2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/editText1"
android:ems="10" />
</RelativeLayout>
If you run this application, and click on the second editText and then back on the first one, it will not trigger the onClick. You can keep selecting back and forth and it will not trigger the onClick at all. I need this basic functionality, but haven't been able to think of a way to get it to work. Ideas?
Notice
I have tried all of the methods recommended on my API level 16 physical device and my API level 8 emulator, but I get the same problem.
Clarification
When editText1 is focused and is clicked on, then the onClick method fires. If editText2 is focussed, and then editText1 is clicked, it doesn't fire. Big problem.
Overview, when a user interacts with any UI component the various listeners are called in a top-down order. If one of the higher priority listeners "consumes the event" then the lower listeners will not be called.
In your case these three listeners are called in order:
OnTouchListener
OnFocusChangeListener
OnClickListener
The first time the user touches an EditText it receives focus so that the user can type. The action is consumed here. Therefor the lower priority OnClickListener is not called. Each successive touch doesn't change the focus so these events trickle down to the OnClickListener.
Buttons (and other such components) don't receive focus from a touch event, that's why the OnClickListener is called every time.
Basically, you have three choices:
Implement an OnTouchListener by itself:
ed1.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(MotionEvent.ACTION_UP == event.getAction())
editTextClicked(); // Instead of your Toast
return false;
}
});
This will execute every time the EditText is touched. Notice that the listener returns false, this allows the event to trickle down to the built-in OnFocusChangeListener which changes the focus so the user can type in the EditText.
Implement an OnFocusChangeListener along with the OnClickListener:
ed1.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if(hasFocus)
editTextClicked(); // Instead of your Toast
}
});
This listener catches the first touch event when the focus is changed while your OnClickListener catches every other event.
(This isn't a valid answer here, but it is a good trick to know.) Set the focusable attribute to false in your XML:
android:focusable="false"
Now the OnClickListener will fire every time it is clicked. But this makes the EditText useless since the user can no longer enter any text...
Note:
getApplicationContext() can create memory leaks. A good habit is to avoid using it unless absolutely necessary. You can safely use v.getContext() instead.
I'm probably too late to the party, but here is a code snipped which fixes the issue with onClick() not being called:
ed1.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP && !v.hasFocus()) {
// onClick() is not called when the EditText doesn't have focus,
// onFocusChange() is called instead, which might have a different
// meaning. This condition calls onClick() when click was performed
// but wasn't reported. Condition can be extended for v.isClickable()
// or v.isEnabled() if needed. Returning false means that everything
// else behaves as before.
v.performClick();
}
return false;
}
});
make edit text clickable..
In XML android:clickable="true"
or in code
ed1.setClickable(true);
then do
ed1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getBaseContext(), "1",Toast.LENGTH_SHORT).show();
}
});
This happens because the first tap gains the focus into the view. The next tap triggers the click.
If you are inflating the view dynamically, do this:
android:clickable="true"
android:focusable="false"
android:focusableInTouchMode="false"
If this doesn't work, try applying it on the parent view as well.
Its the most simplest way to work with date picker.
private DatePickerDialog datePickerDialog;
EditText etJoiningDate;
etJoiningDate=(EditText)findViewById(R.id.etJoiningDate);
etJoiningDate.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
final Calendar cldr = Calendar.getInstance();
int day = cldr.get(Calendar.DAY_OF_MONTH);
int month = cldr.get(Calendar.MONTH);
int year = cldr.get(Calendar.YEAR);
// date picker dialog
datePickerDialog = new DatePickerDialog(TestActivity.this,
new DatePickerDialog.OnDateSetListener() {
#Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
etJoiningDate.setText(dayOfMonth + "/" + (monthOfYear + 1) + "/" + year);
}
}, year, month, day);
datePickerDialog.show();
break;
}
return false;
}
});
public class TestProject extends Activity implements OnClickListener {
TextView txtmsg;
EditText ed1, ed2;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtmsg = (TextView) findViewById(R.id.txtmsg);
ed1 = (EditText) findViewById(R.id.edt1);
ed2 = (EditText) findViewById(R.id.edt2);
ed1.setOnClickListener(this);
ed2.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v==ed1){
txtmsg.setText("1");
Toast.makeText(this, "first",Toast.LENGTH_SHORT).show();
}
if(v==ed2){
txtmsg.setText("2");
Toast.makeText(this, "second",Toast.LENGTH_SHORT).show();
}
}
}
<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" >
<EditText
android:id="#+id/edt1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:ems="10" />
<EditText
android:id="#+id/edt2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/edt1"
android:layout_marginTop="14dp"
android:ems="10" />
<TextView
android:id="#+id/txtmsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="#+id/edt2"
android:layout_below="#+id/edt2"
android:layout_marginRight="22dp"
android:layout_marginTop="160dp"
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>
Took me a minute to figure this out one time when this happened to me. My ImageButton with a setOnClickListener and onClick didn't seem to fire and then I realized it was actually underneath another element in my xml layout, so I turned this:
<RelativeLayout>
<ImageButton>
<LinearLayout></LinearLayout>
</RelativeLayout>
into this:
<RelativeLayout>
<LinearLayout></LinearLayout>
<ImageButton>
</RelativeLayout>
and suddenly the ImageButton was not being overlapped by the other layout since it was now added later to the parent layout and was now on top and works every time. Good luck, always fun when basic stuff suddenly seems to stop working
Avoid using a FocusChangeListener since it will behave erratically when you don't really need it (eg. when you enter an activity). Just set an OnTouchListener along with your OnClickListener like this:
#Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
view.requestFocus();
break;
}
return false;
}
This will cause your EditText to receive focus at first, and your onClick to function properly the first time.
Simple, Reuseable Kotlin Solution
I started with two custom extension functions:
val MotionEvent.up get() = action == MotionEvent.ACTION_UP
fun MotionEvent.isIn(view: View): Boolean {
val rect = Rect(view.left, view.top, view.right, view.bottom)
return rect.contains((view.left + x).toInt(), (view.top + y).toInt())
}
Then listen to touches on the Edittext. This will only fire if initial ACTION_DOWN event was originally on the Edittext, and still is.
myEdittext.setOnTouchListener { view, motionEvent ->
if (motionEvent.up && motionEvent.isIn(view)) {
// Talk your action here
}
false
}

Categories