Prevent Spinner dropdown dismiss when focus changed - android

I have a dropdown spinner which is showed when click on a button looks like this:
<Button
android:id="#+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Spinner
android:id="#+id/spinMenu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:spinnerMode="dropdown"
android:visibility="invisible" />
<ListView
android:id="#+id/lvWall"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Here is snippet showing dropdown popup:
findViewById(R.id.btn).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
spinMenu.performClick();
}
});
My spinner can show dropdown popup correctly. The problem is my layout has a listview which getting data from web service in background. When data is loading completely, all list items will be showed or refreshed, and the spinner's dropdown popup is dismiss (I even don't touch anything on screen). I think the problem is window has changed focus on other view. So how can I prevent it?
Update:
Here is my list after load data from background, it's very simple:
List<Feed> data = result;
FeedAdapter adapter = new FeedAdapter (this, data);
ListView lvWall = (ListView)findViewById(R.id.lvWall);
lvWall.setAdapter(adapter);
And data for spinner:
List<String> list = getMenus();
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, list);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinMenu.setAdapter(dataAdapter);

If I understand correctly, you have a Spinner view which you set as invisible with the only purpose of showing the popup menu, but not the Spinner view itself. In that case, the problem is probably related to this snippet in Spinner.java, more precisely in DropdownPopup.show():
public void show(int textDirection, int textAlignment) {
...
super.show();
...
// Make sure we hide if our anchor goes away.
// TODO: This might be appropriate to push all the way down to PopupWindow,
// but it may have other side effects to investigate first. (Text editing handles, etc.)
final ViewTreeObserver vto = getViewTreeObserver();
if (vto != null) {
final OnGlobalLayoutListener layoutListener = new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (!Spinner.this.isVisibleToUser()) {
dismiss();
} else {
computeContentWidth();
...
What does this mean? Basically that the Spinner is set up with a ViewTreeObserver to be notified whenever a layout pass changes the views in the screen. And if the Spinner is not visible after that happens, the popup is dismissed. Loading the ListView evidently causes a change in the view hierarchy, and it's being fired when the data arrives from the server.
For general usage this is completely logical: if the Spinner is hidden, or it goes off screen, or something like that, it would be reasonable to make the popup go away. However, it's interferring with what you're attempting to do. It would be nice if you could somehow override isVisibleToUser(), but unfortunately it's marked as #hide, so that's not possible.
Might I suggest a workaround, like setting the Spinner visible but really small? Like, with a height of 1px? I believe that should be enough to fool this method.
Another option, and probably a more sensible one, would be to forgo the Spinner altogether and use a PopupMenu instead. You can anchor it to the Button, load it dynamically, and show it when the button is pressed. The visual effect should be the same.

If you think the problem is due to the change of focus . You can set it with multiple ways.
first create a focuschangeListener and onfocuschange do whatever you like
yourView.setOnFocusChangeListener(testListener);
#Override
public void onFocusChange(View arg0,
boolean isFocused)
{
if(isFocused)
{
//do your work here
}
else
{
}
}
And second way to prevent view from focus..
<!-- Dummy item to prevent AutoCompleteTextView from receiving focus -->
<LinearLayout
android:focusable="true" android:focusableInTouchMode="true"
android:layout_width="0px" android:layout_height="0px"/>
<!-- :nextFocusUp and :nextFocusLeft have been set to the id of this component
to prevent the dummy from receiving focus again -->
<AutoCompleteTextView android:id="#+id/autotext"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:nextFocusUp="#id/autotext" android:nextFocusLeft="#id/autotext"/>

Related

Avoiding nested layouts when using a single onClickListener for an item in ListView

The premise is quite simple. I have a list of items, and each item has a TextView containing the title of the item, and a Switch showing whether the item is on or off. Instead of tapping on the Switch to toggle the item being on or off, I want to be able to click anywhere on the item to toggle it. Basically:
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="toggleSwitch">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Switch
android:id="#+id/switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</android.support.constraint.ConstraintLayout>
However, this will create a nested layout when used in a screen, which might be bad for performance. I was wondering, since this ConstraintLayout is literally just a container with an onClick, whether there was a way to implement this layout in a way which avoids nested layouts. Thanks!
You can just give your textView and your button the same method that will be called on click, that way on every view click (anywhere on the item) you will call your method.
For example:
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//change you switch state
}
});
switch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//change you switch state
}
});

OnClickListener/OnTouchListener on LinearLayout inside RecyclerView not called first time after a quick swipe (for up to 3 seconds)

I have an XML like this (I simplified from the original one, but it still reproduces the issue):
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:id="#+id/xContainer"
android:clickable="true" // does not help
android:focusable="true" // does not help
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingBottom="8dp"
android:paddingTop="8dp">
<TextView
android:duplicateParentState="true" // does not help
android:clickable="false" // does not help
android:id="#+id/xText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="8dp"
android:text="#string/xText"
android:textSize="14sp" />
</LinearLayout>
</merge>
and it's included from a CardView like this:
<include layout="#layout/other_stuff_first" />
<include layout="#layout/my_clickable_layout" />
Then I display the item dynamically and attach an OnClickListener to it, in the same method:
public class XViewHolder extends RecyclerView.ViewHolder {
private final View xContainer;
...
public XViewHolder(#NonNull View itemView) {
xContainer = itemView.findViewById(R.id.xContainer);
}
...
private void bindStuff(RecyclerView.ViewHolder holder, int position) {
if (something) {
xContainer.setVisibility(View.VISIBLE);
xContainer.setOnClickListener(v -> {
// do some stuff
});
} else {
xContainer.setVisibility(View.GONE);
xContainer.setOnClickListener(null);
}
}
}
public class ParentAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
...
((XViewHolder) xViewHolder).bindStuff();
}
}
I put some breakpoints, went through the code in the debugger, and it's properly executed (otherwise it would not show up in the UI at all), so the listener is set.
However, the first time when I click the container, most of the time nothing happens. On the consecutive clicks, it works (90% of time on 2nd click and 100% of time on 3rd+ click). I always click in the same way, the container is big, even if I put my whole finger down with a big force, first click doesn't register.
I found several similar questions, but they're either "all or nothing" (whereas in my case it's just sporadic), or due to some other issues. In my app, there's no work on the main thread after the UI is displayed.
Any ideas what can be wrong?
Edit: after some investigation, the issue only happens if:
my_clickable_layout is at the bottom of the scrolling container and not initially visible on screen (only becomes visible after the user scrolls down), AND
the user scrolls down fast, AND
the user taps my_clickable_layout within 0-3 seconds after the scroll.
If the layout is immediately visible, OR user scrolls down slowly, OR user taps more than once, then the taps are dispatched properly.
The RecyclerView itself receives the touch events, because I can always see the logs from the code below, even if I don't see the logs from my children listeners.
recyclerView = view.findViewById(R.id.recycler_view);
recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
Timber.w("onInterceptTouchEvent");
return false;
}
});
At this moment I believe this might be a bug in RecyclerView, which wrongly consumes the first event after a fast scroll - perhaps to detect "end of scrolling" tap?

Multiple EditText in ListView, tap to focus on one EditText and focus jumps to the first

I've got EditTexts in my rows in a ListView. When I tap on one of the EditTexts the soft keyboard appears and the focus jumps to the first EditText in the list instead of staying in the field where I tapped.
Here is a video of it:
https://youtu.be/ZwuFrX-WWBo
I created a completely stripped down app to demonstrate the problem. The full code is here: https://pastebin.com/YT8rxqKa
I'm not doing anything to alter the focus in my code:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.cell_textfield, parent, false);
}
TextView label = (TextView) convertView.findViewById(R.id.textview1);
EditText textfield = (EditText) convertView.findViewById(R.id.textview2);
String text = String.format("Row %d", position);
label.setText(text);
textfield.setText(text);
return convertView;
}
I found another post on StackOverflow giving a workaround for this dumb Android behavior, which involves putting an OnFocusChangedListener on all of the textfields so they can retake focus if it's taken from them improperly.
That worked to regain focus, but then I discovered that when a textfield retakes focus the cursor ends up at the start of the text instead of end, which is unnatural and annoying to my users.
Here is a video of that:
https://youtu.be/A35wLqbuIac
Here's the code for that OnFocusChangeListener. It works to fight the stupid Android behavior of moving focus, but the cursor is misplaced after it regains focus.
View.OnFocusChangeListener onFocusChangeListener = new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View view, boolean hasFocus) {
long t = System.currentTimeMillis();
long delta = t - focusTime;
if (hasFocus) { // gained focus
if (delta > minDeltaForReFocus) {
focusTime = t;
focusTarget = view;
}
}
else { // lost focus
if (delta <= minDeltaForReFocus && view == focusTarget) {
focusTarget.post(new Runnable() { // reset focus to target
public void run() {
Log.d("BA", "requesting focus");
focusTarget.requestFocus();
}
});
}
}
}
};
I hate having to put a bandaid on a bandaid on a bandaid to try to get Android to just behave as it would naturally be expected to behave, but I'll take what I can get.
1) Is there something I can do to fix this problem at the source and not have to have the OnFocusChangeListener at all?
2) If (1) isn't possible, then how can I make sure that when I force focus back to the correct field that I make sure the cursor is placed at the end? I tried using setSelection() right after requestFocus() but since the textfield wasn't yet focused the selection is ignored.
Here was my "solution." In short: ListViews are stupid and will always be a total nightmare when EditTexts are involved, so I changed my Fragment/Adapter code to be able to adapt to either a ListView layout or a ScrollView layout. It only works if you have a small number of rows, because the scrollview implementation isn't able to take advantage of lazy-loading and view recycling. Thankfully, any situation wherein I want EditTexts in a ListView, I rarely have more than 20 rows or so.
When inflating my view in my BaseListFragment, I get my layout id via a method that relies on a hasTextFields() method:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(getLayoutId(), container, false);
return view;
}
public boolean hasTextfields() {
return false;
}
public int getLayoutId() {
if (hasTextfields()) {
return R.layout.scrollfragment;
} else {
return R.layout.listfragment;
}
}
In my various subclasses of my BaseListFragment, if I need to have an EditText in one of my fields, I just override the hasTextFields() method to return true and then my fragment/adapter switchs over to using the basic scrollview implementation.
From there, it's a matter of making sure that the Adapter handles the standard ListView actions for both the ListView and the ScrollView scenarios. Like this:
public void notifyDataSetChanged() {
// If scrollContainer is not null, that means we're in a ScrollView setup
if (this.scrollContainer != null) {
// intentionally not calling super
this.scrollContainer.removeAllViews();
this.setupRows();
} else {
// use the real ListView
super.notifyDataSetChanged();
}
}
public void setupRows() {
for (int i = 0; i < this.getCount(); i++) {
View view = this.getView(i, null, this.scrollContainer);
view.setOnClickListener(myItemClickListener);
this.scrollContainer.addView(view);
}
}
One issue that the click listener presented is that a ListView wants an AdapterView.OnItemClickListener, but arbitrary Views inside a ScrollView want a simple View.OnClickListener. So, I made my ItemClickListener also implement View.OnClickListener and then just dispatched the OnClick to the OnItemClick method:
public class MyItemClickListener implements AdapterView.OnItemClickListener, View.OnClickListener {
#Override
public void onClick(View v) {
// You can either have your Adapter set the tag on the View to be its position
// or you could have your click listener use v.getParent() and iterate through
// the children to find the position. I find its faster and easier to have my
// adapter set the Tag on the view.
int position = v.getTag();
this.onItemClick(null, v, config.getPosition(), 0);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// ...
}
}
Then in MyEditTextListFragment, I create the adapter like this:
listener = createClickListener();
adapter = createListAdapter();
if (scrollContainer != null) {
adapter.setScrollContainer(scrollContainer);
adapter.setMenuItemClickListener(listener);
adapter.setupRows();
} else {
getListView().setOnItemClickListener(listener);
getListView().setAdapter(adapter);
}
Here is my scrollfragment.xml for reference:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:clickable="true"
>
<!--
The following LinearLayout as a focus catcher that won't cause the keyboard to
show without it, the virtual keyboard shows up immediately/always which means we
never get to the enjoy the full size of our screen while scrolling, and
that sucks.
-->
<LinearLayout
android:focusable="true"
android:focusableInTouchMode="true"
android:layout_width="0px"
android:layout_height="0px"/>
<!--
This ListView is still included in the layout but set to visibility=gone. List
fragments require a standard ListView in the layout, so this gets us past that
check and allows us to use the same adapter code in both listview and scrollview
situations.
-->
<ListView android:id="#id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false"
android:background="#null"
android:layout_alignParentTop="true"
android:descendantFocusability="afterDescendants"
android:visibility="gone"
/>
<!--
This scrollview will act as our fake listview so that we don't have to deal with
all the stupid crap that comes along with having EditTexts inside a ListView.
-->
<ScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="afterDescendants"
>
<LinearLayout
android:id="#+id/scrollContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
</LinearLayout>
</ScrollView>
</RelativeLayout>
Try this once, it worked for me:
public void setCursorPosition() {
focusTarget.requestFocus();
focusTarget.setCursorVisible(true);
other.setCursorVisible(false);
} else {
other.setCursorVisible(true);
focusTarget.setCursorVisible(false);
}
}

Is it possible to create a clickable Toast-like notification?

I have a need to show a minimally-intrusive non-blocking notification which is not tied to the activity it was shown in (like a Toast) and which is clickable. Anyone have any idea whether or not this is possible? Unfortunately, it appears that Toast notifications (custom or otherwise) are not clickable (i.e. setting an OnClickListener on its views has no effect). All the alternatives that I'm aware of (i.e. AlertDialog, PopupWindow and Crouton) seem to show a notification which is tied to the activity it was shown in (i.e. they won't continue showing when the activity finishes). Any suggestions?
You can use PopupWindow, add an onClickListener and add a handler to auto cancel it after n times (just like the behavior of a toast). Something like this:
public static void showToast(Activity a, String title, String message) {
// inflate your xml layout
LayoutInflater inflater = a.getLayoutInflater();
View layout = inflater.inflate(R.layout.custom_toast,
(ViewGroup) a.findViewById(R.id.toast_layout_root));
// set the custom display
((TextView) layout.findViewById(R.id.title)).setText(title);
((TextView) layout.findViewById(R.id.message)).setText(message);
// initialize your popupWindow and use your custom layout as the view
final PopupWindow pw = new PopupWindow(layout,
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT, true);
// set windowType to TYPE_TOAST (requires API 23 above)
// this will make popupWindow still appear even the activity was closed
pw.setWindowLayoutType(WindowManager.LayoutParams.TYPE_TOAST);
pw.showAtLocation(layout, Gravity.CENTER | Gravity.TOP, 0, 500);
// handle popupWindow click event
layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// do anything when popupWindow was clicked
pw.dismiss(); // dismiss the window
}
});
// dismiss the popup window after 3sec
new Handler().postDelayed(new Runnable() {
public void run() {
pw.dismiss();
}
}, 3000);
}
xml layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toast_layout_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000"
android:orientation="vertical"
android:elevation="10dp"
android:padding="20dp">
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#FFF"
android:textStyle="bold"/>
<TextView
android:id="#+id/message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#FFF"/>
</LinearLayout>
You are right, a Toast object has no way to be interacted with, but there are many libraries out there that will give you the same look and feel as a toast, but with some interactivity. The one I use is https://github.com/JohnPersano/SuperToasts
I think what you need is in fact a PopupWindowwhich can be seen here "http://developer.android.com/reference/android/widget/PopupWindow.html".
Toasts have a very specific task, which is to inform the user, without any input from them. So instead of trying to extend the purpose of the Toast, use the PopupWindow which can be interacted with by the user.
A 'Dialog' type of activity will probably be your best bet.
In manifest:
<activity android:name=".ToastLikeActivity"
android:theme="#android:style/Theme.Dialog"
android:label="#string/label"
></activity>
And timeout the activity within the onCreate():
class ToastLikeActivity extends Activity {
#Override
public void onCreate(Bundle state)
// auto-kill activity after X seconds <-------------------------
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
ToastLikeActivity.this.finish(); // kill after X seconds
}
}
}, VisibleTimeSecs*1000);
}
To display the dialog start it as with any other activity:
Intent i = new Intent(this, ToastLikeActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
And it will show up and automatically go away after X seconds.
Such a popup will not be tied to the caller activity. In fact - it will not even require a caller activity. You
can activate it (bad idea, but possible) even from a service.
You can implement basically any kind of sensitive (i.e. accepting user's clicks) interface you want to
the ToastLikeActivity. Especially: you can make its exteriors transparent, giving it a dialog-likke looks.

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