Prevent a ToggleButton from changing state onClick - android

This question is similar to this. However it did not solve my problem.
I have a ToggleButton and when a user clicks, I do not want to change the state of the ToggleButton, as I am programatically changing the state from another Activity.
How do I override it?
Here is my Activity code:
<ToggleButton
android:id="#+id/alarm1"
android:background="#drawable/check"
android:layout_alignParentLeft="true"
android:layout_margin="8dp"
android:textOn=""
android:onClick="alarmSet1"
android:textOff=""
android:focusable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Here is the Java code:
public void alarmSet1(View view)
{
int a1=1;
int idTime = (int) System.currentTimeMillis();
Intent intent = new Intent(MainActivity.this, AddAlarm.class);
intent.putExtra("pendInt",idTime);
intent.putExtra("tts",a1);
startActivity(intent);
}

I am late to the party, but I had the exact same question and the given answer didn't fit my needs, so I made something myself.
What I wanted (correct me if this was not the original question):
I want to intercept clicks/swipes on a Switch, RadioButton, CheckBox or any other CompoundButton, making sure the button itself doesn't toggle state, but instead calling a function which will eventually lead to the correct state being set programatically. (eg. using LiveData) so the state of the button is always the same as the state of the data it toggles.
What I made:
/**
* Use this if you want your compoundButton to do something when (un) checked,
* but not change it's state by itself.
*
* It will block the actual changing of the button, but instead run [onCheckedChanged]
* which should in turn eventually lead to setting `isChecked` to get proper setting of the switch
* after its action has been performed
* This might cause some trouble as it will trigger on programmatic sets outside of this listener.
* To get around that, use [setIsCheckedWithoutBypassedListener] if you don't want that to happen.
*/
fun CompoundButton.setInterceptedOnCheckedChangedListener(onCheckedChanged: CompoundButton.OnCheckedChangeListener){
compoundButtonListeners[this] = onCheckedChanged
setOnCheckedChangeListener { compoundButton, b ->
compoundButton.isChecked = !compoundButton.isChecked
onCheckedChanged.onCheckedChanged(compoundButton, b)
}
}
/**
* Set value without triggering the listener added in [setInterceptedOnCheckedChangedListener]
*/
fun CompoundButton.setIsCheckedWithoutBypassedListener(isChecked: Boolean){
compoundButtonListeners[this]?.let{ l ->
setOnCheckedChangeListener(null)
this.isChecked = isChecked
setOnCheckedChangeListener(l)
}
}
/**
* Holds the OnCheckedChangeListeners for the compoundbuttons, as they are private and cannot
* be retreived otherwise.
*/
private val compoundButtonListeners = WeakHashMap<CompoundButton, CompoundButton.OnCheckedChangeListener>()
If this ends up putting a lot of _, _ ->'s in your code, feel free to replace the CompoundButton.OnCheckedChangeListener with a View.OnClickListener.
Leaving this here in case somebody else has the same question as I had.
I am pretty sure using a WeakHashMap prevents a memory leak that would happen on recreating activity. If this is not the case, please educate me :)

It is simple:
Create a CompoundButton.OnCheckedChangeListener and override onCheckedChanged like this:
private CompoundButton.OnCheckedChangeListener _toggleButtonListener = new CompoundButton.OnCheckedChangeListener()
{
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
compoundButton.setChecked(false);
// And now, do whatever you want.
}
};
Of course, you have to attach the listener to your button:
... somewhere in the onCreate() method:
ToggleButton toggleButton=findViewById(R.id.alarm1);
toggleButton.setOnCheckedChangeListener(_toggleButtonListener);
And thats it.
Keep coding, and let the code be with you!

Related

Add preferences to specific places in PreferenceScreen programmatically

I am populating parts of my preferences programmatically. This works fine. Unfortunately new preferences there has to be added, when the user changes some preferences (think of an 'add a new alarm'-preference). This works fine as well, when I use PreferenceCategories (because the new ones are added at the end of one such, so myPreferenceCategory.addPreference(newPreference) does the trick). But what can I do to programmatically add a Preference to any specific place (not just the end of usual categories/the prefScreen??
I tried to use some kind of "invisible" PreferenceCategory, by setting android:layout="my_custom_invis_layout" with
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/my_custom_invis_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="0dp"
android:paddingTop="0dp"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"/>
Unfortunately those padding and margin does not seem to have an impact on the minimum space the empty category take (but do so with positive values, which is - of cause - of no help).
I tried as well to nullify the layout by
<PreferenceCategory
android:layout="#null">
but this just enlarges the space the category takes to those the other preferences have.
Unfortunately SO did not help me on this so far. I would be very happy if anyone can point me to something like "add a preference A below preference B" or on how to make a category taking no space at all (as this would resolve my problem as well).
I see this question is quite old, but since I was facing a similar problem and managed to solved it, I figured there would be no harm done by posting anyway.
The way I solved this is by adding the Preference (in my case a category that needed to be added in a particular spot amongst the other categories) in xml from the start, removing it programmatically if not yet needed. When putting it back (programmatically) afterwards, it appears at the same position it was before removing it. Haven't tried your particular case (with single Preferences needing to go in a particular spot within a category), but I bet it works the same way.
public class PreferencesFragment extends PreferenceFragmentCompat {
private SharedPreferences mSharedPreferences;
private PreferenceCategory mPreferenceCategory;
#Override
public void onCreatePreferences(#Nullable Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences);
mPreferenceCategory = (PreferenceCategory) findPreference("preferenceCategoryKey");
if (preferenceNotRequiredYet) {
removePreferenceCategory();
}
// an I have a SharedPreferenceListener attached that calls
// addPreferenceCategory when I need to add it back
}
private void removePreferenceCategory() {
PreferenceScreen parentScreen = (PreferenceScreen) findPreference("parent_screen_key");
parentScreen.removePreference(mPreferenceCategory);
}
private void addPreferenceCategory() {
PreferenceScreen parentScreen = (PreferenceScreen) findPreference("parent_screen_key");
parentScreen.addPreference(mPreferenceCategory);
}
}
Ok, I've tried that other approach with Preferences#setOrder(int). (I left the previous answer there, cause for some use cases it might be the easier solution.) Does this one better suit your needs?
public class PreferencesFragment extends PreferenceFragmentCompat {
private SharedPreferences mSharedPreferences;
PreferenceCategory mMyPreferenceCategory;
// ArrayList to keep track of the currently added Preferences
ArrayList<Preference> mPreferenceList = new ArrayList<>();
// this counter only serves for name-giving of the added
// Preferences in this example
int mCounter = 0;
#Override
public void onCreatePreferences(#Nullable Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences);
mMyPreferenceCategory = (PreferenceCategory) findPreference("preferenceCategoryKey");
addPreference(null);
}
// adds a Preference that is inserted on the position of the
// clicked Preference, moving the clicked Preference - and all
// Preferences after - one position down
private void addPreference(Preference pref) {
int order = 0;
if (pref != null) {
order = pref.getOrder();
}
for (Preference preference : mPreferenceList) {
int oldOrder = preference.getOrder();
if (oldOrder >= order) {
preference.setOrder(oldOrder+1);
}
}
Preference newPreference = new Preference(getContext());
newPreference.setTitle("Preference " + mCounter);
newPreference.setOrder(order);
newPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
addPreference(preference);
return false;
}
});
mMyPreferenceCategory.addPreference(newPreference);
mPreferenceList.add(newPreference);
mCounter++;
}
}

android databinding: how to avoid onCheckedChanged triggered by programmatically

I am now trying to use android data-binding in my project, and encounter this kind of issue, for example: I have 3 checkbox as a checkbox group, if first checkbox is checked, then a variable type is 1. the second makes type to 2, the 3rd makes type to 3. so I implement the code in this way.
// layout.xml
<android.support.v7.widget.AppCompatCheckBox
android:layout_width="50dp"
android:layout_height="50dp"
android:checked="#{userInfoViewModel.type == 1}"
android:onCheckedChanged="#{(compoundButton, checked) -> userInfoViewModel.onTypeChecked(checked, 1)}"
/>
<android.support.v7.widget.AppCompatCheckBox
android:layout_width="50dp"
android:layout_height="55dp"
android:checked="#{userInfoViewModel.type == 2}"
android:onCheckedChanged="#{(compoundButton, checked) -> userInfoViewModel.onTypeChecked(checked, 2)}"
/>
<android.support.v7.widget.AppCompatCheckBox
android:layout_width="50dp"
android:layout_height="55dp"
android:checked="#{userInfoViewModel.type == 3}"
android:onCheckedChanged="#{(compoundButton, checked) -> userInfoViewModel.onTypeChecked(checked, 3)}"
/>
// viewModel
public void onTypeChecked(boolean checked, int i) {
if (checked) {
// if it is a check. set the type
type.set(i);
} else {
// if it is a uncheck. set type to unknown
type.set(0);
}
}
Now the problem is that, if I have checked 1st checkbox, then I check the 2nd. type should be set to 2, and the UI should update correctly. But the reality is that uncheck event also occur on the 1st checkbox, after type is set to 2, then type.set(0) is triggered, so no checkbox is checked.
In fact, this issue is same to onCheckedChanged called automatically. What I need is a solution for data-binding.
In non-data-binding project, I think the best solution is using setCheckedSilent(answer by #Emanuel Andrada).
public void setCheckedSilent(boolean checked) {
super.setOnCheckedChangeListener(null);
super.setChecked(checked);
super.setOnCheckedChangeListener(listener);
}
But in data-binding, I can not do this. So is there any expert can help me out?
According to #Arpan Sharma's answer, listen to onClick instead of onCheckedChanged. This solution works currently, But I am worried about the value of checked, is it always right?
public void onTypeChecked(View view, int i) {
Boolean checked = ((CheckBox) view).isChecked();
if (checked) {
type.set(i);
} else {
type.set(0);
}
}
Expose an ObservableBoolean from the ViewModel, then use two-way databinding over that boolean.
Then you can use the ObservableBoolean's values to decide what you want to do, rather than encode it in the XML.
android:checked="#={vm.checkedValue}"
This is very simple with data binding
In xml checkbox component
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onCheckedChanged="#{(compoundButton, checked) ->
changeKeyboardVM.onCheckedChange(compoundButton, checked)}" />
In ViewModel or Activity
public void onCheckedChange(CompoundButton button, boolean check) {
Log.d("Z1D1", "onCheckedChange: " + check);
}
now Boolean check true on checked
and false on unchecked
I faced the same problem and i used onCLick listener instead onCHeck
listener .That way the listener wont change the check state when it is set programatically.
In your problem you should try setting different check change listeners to your check boxes.
I came across this question for first time and I think it's better to be implemented using binding adapter.
Here is the code for binding adapter
interface OnUserCheckedChangeListener {
fun onUserCheckChange(view:CompoundButton, isChecked:Boolean)
}
#BindingAdapter("onUserCheckedChange")
fun setUserCheckedChangeListener(view:CompoundButton, listener: OnUserCheckedChangeListener?){
if(listener == null){
view.setOnClickListener(null)
}else{
view.setOnClickListener {
listener.onUserCheckChange(view, view.isChecked)
}
}
}
And we can use it on any compound button
<CheckBox
android:id="#+id/finish_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
android:checked="#{your_condition}"
onUserCheckedChange="#{(view, checked) -> vm.onItemChecked(todo, checked)}"
/>
Using onClick instead of onCheckedChanged to prevent 2-ways binding.
From item_order_view.xml:
<data>
<variable
name="viewModel"
type="com.package.name.OrderItemViewModel" />
</data>
<CheckBox
android:id="#+id/cb_selected"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="8dp"
android:buttonTint="#color/white"
android:checked="#{viewModel.isSelect}"
android:onClick="#{() -> viewModel.onClickedCheckBox()}"
android:textColor="#color/white" />
From OrderItemViewModel.java
public class OrderItemViewModel {
public final ObservableField<Boolean> isSelect;
public final OrderItemViewModelListener mListener;
private final Order mOrder;
public OrderItemViewModel(Order order, OrderItemViewModelListener listener) {
this.mListener = listener;
this.mOrder = order;
isSelect = new ObservableField<>(mOrder != null ? mOrder.isSelect() : false);
}
/**
* Using onClick instead of onCheckedChanged
* to prevent 2-ways binding issue.
*/
public void onClickedCheckBox() {
mListener.onCheckChanged();
}
public interface OrderItemViewModelListener {
void onCheckChanged();
}
}
See https://stackoverflow.com/a/52606437/2914140:
Write inside OnCheckedChangeListener:
if (button.isPressed()) {
// A user pressed Switch.
}
Maybe some answers from How to use data binding for Switch onCheckedChageListener event? may help, for instance, defining android:onCheckedChanged listener, but I didnt test.

Can a RadioGroup span more than one layout?

I have sucessfully made and used RadioGroup's before in xml, but each time there was a set of radio buttons in succession, all within the same LinearLayout. Now I wish to define a set of radio buttons to be part of a group, but they are not in the same layout. My start and end code for the group is:
START:
<RadioGroup android:id="#+id/radioGroup1" >
END:
</RadioGroup>
If I place this around each button individually, then it compiles, but the buttons don't act as radio buttons (i.e. activating one did not de-activate the others). If I try to place the "start" before any of the buttons and put the "end" after the last of them, then I get compilation errors.
Store the RadioButtons in an array. Instead of grouping them in a RadioGroup, you have to enable/disable them yourself. (un-tested so no copying/pasting )
declare these variables
private ArrayList<RadioButton> mGroup = new ArrayList<RadioGroup>();
private CompoundButton.OnCheckedChangeListener mListener = new CompoundButton.OnCheckedChangeListener()
{
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
for(RadioButton btn : mGroup)
btn.setChecked(false);
buttonView.setChecked(true);
}
}
Somewhere in your activity:
mGroup.add(your radiobuttons); // e.g. (RadioButton)findViewById(R.id.radio_button1);
mGroup.add(another radiobutton);
for(RadioButton btn : mGroup)
btn.setOnCheckedChangeListener(mListener)
Maybe you have to invalidate your Buttons after checking/unchecking them, to cause a redraw
Unfortunately the SDK does not directly support doing this, you would need to create a custom "group" to manager the buttons.
All the mutual exclusion logic for each RadioButton is managed by RadioGroup, so all the buttons have to be added to the same group. RadioGroup is a subclass of LinearLayout, so this inherently means they also need to all be in the same layout. RadioGroup manages each button's checked status by iterating through its children, which is why the two can't be divorced.
Here is a link to the RadioGroup source code as a starting point, you could create a custom Manager that uses the same logic here to manage the status of which button is checked in order to separate them from their layout status. RadioGroup basically just registers itself as an OnCheckedChangeListener for each child that is a RadioButton and then controls the check status of all the buttons based on user events.
HTH
Here's a refined and tested version of the first part of Entreco's code:
final ArrayList<RadioButton> mGroup = new ArrayList<RadioButton>();
CompoundButton.OnCheckedChangeListener mListener = new CompoundButton.OnCheckedChangeListener()
{
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
for(RadioButton btn : mGroup) {
if (buttonView.getId() != btn.getId() && isChecked) {
btn.setChecked(false);
}
}
}
};
It will uncheck only the other buttons and only if the state of the clicked button changed from unchecked to checked.
#Entreco answer can cause recursive call to onCheckedChanged which is fixed by #Twilite answer.
But #Twilite answer also has a problem and that's the id of views without explicit id may not be unique. If that happen, you may see either multiple selected radio buttons or none of them being checked. So, it's safer to either set a unique id or a unique tag for each one:
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
if (isChecked) {
for (RadioButton btn : mGroup)
if (!btn.getTag().equals(compoundButton.getTag()))
btn.setChecked(false);
}
}

Disable an ImageButton

This looks easy, but I'm not able to disable an ImageButton. It continues to receive click events, and its appearance don't change like a standard Button would.
There are some similar questions on SO, but they don't help me.
Even with a very simple layout like this :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ImageButton
android:id="#+id/btn_call"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:clickable="false"
android:enabled="false"
android:src="#android:drawable/sym_action_call" />
</LinearLayout>
The button is still enabled and I can click it.
What's strange is that if I change the ImageButton to a simple Button, then it works as expected. The button becomes disabled and unclickable. I don't understand. Does anyone have an idea?
Here's the code I use to disable an ImageButton and make it look grayed out:
/**
* Sets the specified image buttonto the given state, while modifying or
* "graying-out" the icon as well
*
* #param enabled The state of the menu item
* #param item The menu item to modify
* #param iconResId The icon ID
*/
public static void setImageButtonEnabled(Context ctxt, boolean enabled, ImageButton item,
int iconResId) {
item.setEnabled(enabled);
Drawable originalIcon = ctxt.getResources().getDrawable(iconResId);
Drawable icon = enabled ? originalIcon : convertDrawableToGrayScale(originalIcon);
item.setImageDrawable(icon);
}
/**
* Mutates and applies a filter that converts the given drawable to a Gray
* image. This method may be used to simulate the color of disable icons in
* Honeycomb's ActionBar.
*
* #return a mutated version of the given drawable with a color filter
* applied.
*/
public static Drawable convertDrawableToGrayScale(Drawable drawable) {
if (drawable == null) {
return null;
}
Drawable res = drawable.mutate();
res.setColorFilter(Color.GRAY, Mode.SRC_IN);
return res;
}
Simply call setImageButtonEnabled(); the only downside is you need the image's resource ID in here because it's not possible to revert a transformed icon back into the original.
ImageButton has different inheritance chain meaning it does not extend Button:
ImageButton < ImageView < View
It continues to receive click events
Here is what happens when you set a click listener for the View:
public void setOnClickListener(OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
mOnClickListener = l;
}
So if you set a listener the android:clickable="false" changes to android:clickable="true".
and its appearance don't change like a standard Button would
You should supply a drawable state list to the view so it could set an appropriate image based on android:enabled. Do you have this? Or you have the only image for your button?
EDIT: You can find info on StateListDrawable here. android:state_enabled is what you need to use in the list in order to tell the OS what image to use for that state.
EDIT2: Since you really need to add a listener you can make a check inside of the listener if (!isEnabled()) { return; } else { /* process the event */ }.
if you want to disable an image button,on click event, set the the property "setEnabled" to false
Ex: imgButton.setEnabled(false);
Make sure there is no view with same id in your view hierarchy and you do not add any click listener to that view.
Taking advantage of the Oleg Vaskevich's answer. Can be made an answer for Kotlin.
Make a Extension Function for ImageButton, this way:
/**
* Sets the specified image buttonto the given state, while modifying or
* "graying-out" the icon as well
*
* #param enabled The state of the menu item
* #param iconResId The icon ID
*/
fun ImageButton.setButtonEnabled(enabled: Boolean, iconResId: Int) {
isEnabled = enabled
val originalIcon = context.resources.getDrawable(iconResId)
val icon = if (enabled) originalIcon else convertDrawableToGrayScale(originalIcon)
setImageDrawable(icon)
}
And you get a little less reliant on providing Context
I managed to build a solution inspired by Oleg Vaskevich's answer, but without the need to pass drawable resource ID to setEnabled().
Here is Kotlin code, inside of utility module:
fun Drawable.deepCopy(): Drawable =
constantState?.newDrawable()?.mutate() ?:
throw RuntimeException("Called on null Drawable!")
fun Drawable.toGrayscale(): Drawable =
deepCopy().apply { setColorFilter(Color.GRAY, PorterDuff.Mode.SRC_IN) }
fun ImageButton.setAndShowEnabled(enabled: Boolean) {
if (enabled == isEnabled)
return
isEnabled = enabled
if (enabled) {
setImageDrawable(tag as Drawable)
}
else {
if (tag == null)
tag = drawable
setImageDrawable(drawable.toGrayscale())
}
}
It can be used like this:
val button: ImageButton = findViewById(...)
// ...
button.setAndShowEnabled(false)
// launch async operation
GlobalScope.launch {
// do work here
// unblock button
button.setAndShowEnabled(true)
}
As other answers have said, you cannot disable an ImageButton in the layout XML as you can a Button, but you can disable both the same way at runtime:
In Java:
button.setEnabled(false); // setEnabled(boolean) on TextView
imgButton.setEnabled(false); // setEnabled(boolean) on View
In both cases the button is disabled -- no click events get to its onClickListener.
You can also change the icon color of the disabled ImageButton the same way you change the text color on a disabled Button, assuming the icon is tintable.
In the layout XML:
<Button
...
android:textColor="#drawable/button_color_selector" />
<ImageButton
...
android:tint="#drawable/button_color_selector" />
Now setEnable(boolean) on the Button or ImageButton changes the text or icon color according to the states in your button_color_selector.xml
To improve on Ivan's 2018 answer: This is a much simpler method (Kotlin):
fun ImageButton.setAndShowEnabled(enabled: Boolean) {
val filter = PorterDuffColorFilter(GRAY, PorterDuff.Mode.SCREEN)
if (enabled == this.isEnabled)
return
this.isEnabled = enabled
if (enabled) {
drawable.colorFilter = null // Removes the filter.
} else {
drawable.mutate() // Repeated calls are no-ops.
drawable.colorFilter = filter
}
}

How to remove focus without setting focus to another control?

I like my UIs to be intuitive; each screen should naturally and unobtrusively guide the user on to the next step in the app. Barring that, I strive to make things as confusing and confounding as possible.
Just kidding :-)
I've got three TableRows, each containing a read-only and non-focusable EditText control and then a button to its right. Each button starts the same activity but with a different argument. The user makes a selection there and the sub-activity finishes, populating the appropriate EditText with the user's selection.
It's the classic cascading values mechanism; each selection narrows the available options for the next selection, etc. Thus I'm disabling both controls on each of the next rows until the EditText on the current row contains a value.
I need to do one of two things, in this order of preference:
When a button is clicked, immediately remove focus without setting focus to a different button
Set focus to the first button when the activity starts
The problem manifests after the sub-activity returns; the button that was clicked retains focus.
Re: #1 above - There doesn't appear to be a removeFocus() method, or something similar
Re: #2 above - I can use requestFocus() to set focus to the button on the next row, and that works after the sub-activity returns, but for some reason it doesn't work in the parent activity's onCreate().
I need UI consistency in either direction--either no buttons have focus after the sub-activity finishes or each button receives focus depending on its place in the logic flow, including the very first (and only) active button prior to any selection.
Using clearFocus() didn't seem to be working for me either as you found (saw in comments to another answer), but what worked for me in the end was adding:
<LinearLayout
android:id="#+id/my_layout"
android:focusable="true"
android:focusableInTouchMode="true" ...>
to my very top level Layout View (a linear layout). To remove focus from all Buttons/EditTexts etc, you can then just do
LinearLayout myLayout = (LinearLayout) activity.findViewById(R.id.my_layout);
myLayout.requestFocus();
Requesting focus did nothing unless I set the view to be focusable.
Old question, but I came across it when I had a similar issue and thought I'd share what I ended up doing.
The view that gained focus was different each time so I used the very generic:
View current = getCurrentFocus();
if (current != null) current.clearFocus();
You can use View.clearFocus().
Use View.requestFocus() called from onResume().
android:descendantFocusability="beforeDescendants"
using the following in the activity with some layout options below seemed to work as desired.
getWindow().getDecorView().findViewById(android.R.id.content).clearFocus();
in connection with the following parameters on the root view.
<?xml
android:focusable="true"
android:focusableInTouchMode="true"
android:descendantFocusability="beforeDescendants" />
https://developer.android.com/reference/android/view/ViewGroup#attr_android:descendantFocusability
Answer thanks to:
https://forums.xamarin.com/discussion/1856/how-to-disable-auto-focus-on-edit-text
About windowSoftInputMode
There's yet another point of contention to be aware of. By default,
Android will automatically assign initial focus to the first EditText
or focusable control in your Activity. It naturally follows that the
InputMethod (typically the soft keyboard) will respond to the focus
event by showing itself. The windowSoftInputMode attribute in
AndroidManifest.xml, when set to stateAlwaysHidden, instructs the
keyboard to ignore this automatically-assigned initial focus.
<activity
android:name=".MyActivity"
android:windowSoftInputMode="stateAlwaysHidden"/>
great reference
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/ll_root_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
LinearLayout llRootView = findViewBindId(R.id.ll_root_view);
llRootView.clearFocus();
I use this when already finished update profile info and remove all focus from EditText in my layout
====> Update: In parent layout content my EditText add line:
android:focusableInTouchMode="true"
What about just adding android:windowSoftInputMode="stateHidden" on your activity in the manifest.
Taken from a smart man commenting on this: https://stackoverflow.com/a/2059394/956975
I tried to disable and enable focusability for view and it worked for me (focus was reset):
focusedView.setFocusable(false);
focusedView.setFocusableInTouchMode(false);
focusedView.setFocusable(true);
focusedView.setFocusableInTouchMode(true);
First of all, it will 100% work........
Create onResume() method.
Inside this onResume() find the view which is focusing again and again by findViewById().
Inside this onResume() set requestFocus() to this view.
Inside this onResume() set clearFocus to this view.
Go in xml of same layout and find that top view which you want to be focused and set focusable true and focusableInTuch true.
Inside this onResume() find the above top view by findViewById
Inside this onResume() set requestFocus() to this view at the last.
And now enjoy......
android:focusableInTouchMode="true"
android:focusable="true"
android:clickable="true"
Add them to your ViewGroup that includes your EditTextView.
It works properly to my Constraint Layout. Hope this help
You could try turning off the main Activity's ability to save its state (thus making it forget what control had text and what had focus). You will need to have some other way of remembering what your EditText's have and repopulating them onResume(). Launch your sub-Activities with startActivityForResult() and create an onActivityResult() handler in your main Activity that will update the EditText's correctly. This way you can set the proper button you want focused onResume() at the same time you repopulate the EditText's by using a myButton.post(new Runnable(){ run() { myButton.requestFocus(); } });
The View.post() method is useful for setting focus initially because that runnable will be executed after the window is created and things settle down, allowing the focus mechanism to function properly by that time. Trying to set focus during onCreate/Start/Resume() usually has issues, I've found.
Please note this is pseudo-code and non-tested, but it's a possible direction you could try.
You do not need to clear focus, just add this code where you want to focus
time_statusTV.setFocusable(true);
time_statusTV.requestFocus();
InputMethodManager imm = (InputMethodManager)this.getSystemService(Service.INPUT_METHOD_SERVICE);
imm.showSoftInput( time_statusTV, 0);
Try the following (calling clearAllEditTextFocuses();)
private final boolean clearAllEditTextFocuses() {
View v = getCurrentFocus();
if(v instanceof EditText) {
final FocusedEditTextItems list = new FocusedEditTextItems();
list.addAndClearFocus((EditText) v);
//Focus von allen EditTexten entfernen
boolean repeat = true;
do {
v = getCurrentFocus();
if(v instanceof EditText) {
if(list.containsView(v))
repeat = false;
else list.addAndClearFocus((EditText) v);
} else repeat = false;
} while(repeat);
final boolean result = !(v instanceof EditText);
//Focus wieder setzen
list.reset();
return result;
} else return false;
}
private final static class FocusedEditTextItem {
private final boolean focusable;
private final boolean focusableInTouchMode;
#NonNull
private final EditText editText;
private FocusedEditTextItem(final #NonNull EditText v) {
editText = v;
focusable = v.isFocusable();
focusableInTouchMode = v.isFocusableInTouchMode();
}
private final void clearFocus() {
if(focusable)
editText.setFocusable(false);
if(focusableInTouchMode)
editText.setFocusableInTouchMode(false);
editText.clearFocus();
}
private final void reset() {
if(focusable)
editText.setFocusable(true);
if(focusableInTouchMode)
editText.setFocusableInTouchMode(true);
}
}
private final static class FocusedEditTextItems extends ArrayList<FocusedEditTextItem> {
private final void addAndClearFocus(final #NonNull EditText v) {
final FocusedEditTextItem item = new FocusedEditTextItem(v);
add(item);
item.clearFocus();
}
private final boolean containsView(final #NonNull View v) {
boolean result = false;
for(FocusedEditTextItem item: this) {
if(item.editText == v) {
result = true;
break;
}
}
return result;
}
private final void reset() {
for(FocusedEditTextItem item: this)
item.reset();
}
}

Categories

Resources