I'm trying to determine whether a SearchView in the ActionBar is focused. But when I call SearchView.isFocused() I always get false as a result, even when the view is really focused (there is a cursor inside, and the soft keyboard is shown).
How can I check, whether a SearchView is focused?
After some researching, I learned that SearchView.isFocused() always returns false because it's some child of the SearchView who really has the focus, not the SearchView itself. So I use the following code to check the focus of a SearchView:
private boolean checkFocusRec(View view) {
if (view.isFocused())
return true;
if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
if (checkFocusRec(viewGroup.getChildAt(i)))
return true;
}
}
return false;
}
So I call checkFocusRec(searchView) to check for the focus. I'm not sure this is the optimal solution but it works for me.
Looks like an ugly (or bug) implementation from SearchView. My suggestion is to extend the SearchView and create methods like so:
var isQueryFocused = false
private set
// you can also override hasFocus() and isFocused() methods, if you prefer
fun hasQueryFocus() = isQueryFocused
override fun setOnQueryTextFocusChangeListener(listener: OnFocusChangeListener?) {
super.setOnQueryTextFocusChangeListener { v, hasFocus ->
isQueryFocused = hasFocus
listener?.onFocusChange(v, hasFocus)
}
}
The other answers use recursive calls which is not a very efficient and private resource ID (the inner TextView id) which is a bad practice.
When looking at this question and its solution, I found some extra information in the resource files included with the Android SDK (in the folder sdk/platforms/android-xx/data/res/layout/search_view.xml).
The subview holding focus has id #+id/search_src_text and is of type android.widget.SearchView$SearchAutoComplete.
I would therefore suggest the following alternative to the previous solution:
private boolean isSearchViewFocused(SearchView sview) {
View et_search = sview.findViewById(R.id.search_src_text);
return et_search.isFocused();
}
Related
I am building a todo application. My goal is for the item's background color to change to red and the font to white, if urgent = true (boolean).
I am able to do this, but unfortunately once it changes the true todo, it will also change the todo before, even if it equals false.
I know the issue is in the getView method (see below). I have tried moving the textView = newView.findViewById(R.id.textView), above the if old == null statement, but that seems to crash the app. I have also moved the if urgent == true statement into the other if statement, and that won't work either.
Any ideas what may be causing the issue?
#Override
public View getView(int position, View old, ViewGroup parent) {
View newView = old;
LayoutInflater inflater = getLayoutInflater();
if(old == null) {
newView = inflater.inflate(R.layout.todo_items, parent, false);
}
textView = newView.findViewById(R.id.textView);
textView.setText(getItem(position).toString());
if(urgent == true) {
newView.setBackgroundColor(Color.RED);
textView.setTextColor(Color.WHITE);
}
return newView;
}
}
You need an array of booleans to keep track of the state for each item in the listview
Try changing
if(urgent == true) {
newView.setBackgroundColor(Color.RED);
textView.setTextColor(Color.WHITE);
}
To
if(urgent[position]) {
newView.setBackgroundColor(Color.RED);
textView.setTextColor(Color.WHITE);
} else {
//Put here the default colors
newView.setBackgroundColor( );
textView.setTextColor( );
}
this should fix the issue, also you don't need to do if(boolean == true) if(boolean) is enough
I think you need to have an array (or list) of urgent variables, for each position in the list. When item in the list is updated by scroll of by other reason, all views are updated according to the one urgent var.
I have a view. The view might become visible at some time in the future. When this view is visible I want to call a method. How to do this?
val editText = findViewById<EditText>(R.id.editText)
// editText might become invisible in some time in future
// and in some in future it might visible
if(editText.isVisible(){
// code to be executed
}
Code for View.isVisible() :
fun View.isVisible() = this.visibility == View.VISIBLE // check if view is visible
Is there anything like View.setOnClickListener which could be applied and triggered when the view is visible-
editText.setOnClickListener { view ->
}
click listener is callback when the view is being clicked. it has no concern with its visibility. There is no method like isVisible(). to check Visibility
if(yourView.getVisiblity()==View.VISIBLE){ //your task}
for kotlin:
if(youView.visibility==View.VISIBLE){//your task}
I might initialize a variable int status of visibility and set it to 0 with the view invisible.
Now I would create a function instead directly setting the visibility of the view.
For example a function named onVisibilityChanged();
In that function add the set visibility code followed by setting the int to 0 or 1 as per the visibility an if-else block.
If you just set the view to visible, set the int to 1.
The reason for adding if-else block is to configure your actions based on the visibility status.
So that gives you the freedom to do whatever you want bases on the visibility.
Make sure you add this code in such a way that it is executed anytime you want.
Use the performClick() function to click any button or any other view.
I hope you understand. Or comment any query. I would have posted the code for the same but it looks like you are using Kotlin. So I'll try to post it in Kotlin if possible.
The main intention of doing such a thing is when the value of int changes, the app knows what to do and also knows that visibility has changed.
Just call the function wherever you want. It will be easy.
So this is what I am trying to do:
int visibilityStatus;
textview = findViewById(R.id.textview);
getInitialVisibility();
funcOnVisibilityChange();
}
private void getCurrentVisibility() {
if (textview.getVisibility() == View.VISIBLE) {
visibilityStatus = 1;
} else {
visibilityStatus = 0;
}
}
private void funcOnVisibilityChange() {
//Now change the visibility in thia function
textview.setVisibility(View.VISIBLE);
int currentVisibilityStatus;
if (textview.getVisibility() == View.VISIBLE) {
currentVisibilityStatus = 1;
} else {
currentVisibilityStatus = 0;
}
if (visibilityStatus != currentVisibilityStatus) {
//Visibility status has changed. Do your task
else {
//visibility status not changed
}
}
}
So all that we are doing is getting visibility of the view when the app is started and when you somehow change its visibility. Here in the example, I've directly changed the visibility. So wherever you know that visibility is going to change just put the funcOnVisibilityChange() and it will do your job... hope it helps. Let me know if you need more clarification.
I got JSON response which have elementId and flag for hide/show that element
Call function using this(From JSON Response)
displayView(templateDefinationItem.getTemplateDefinationId(), templateDefinationItem.isActive());
I have created one function for hide the views
public void displayView(final int elementId, boolean isVisible) {
try {
View view = findViewById(elementId);
if (isVisible) {
view.setVisibility(View.VISIBLE);
} else {
view.setVisibility(View.GONE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
In above code i passed elementId and true/false value for the operation, where
elementId of(EditTextId,TextView,LinearLayout,Buttons etc.)
Error
i got error in this line View view = findViewById(elementId); getting null.
What i want
is there any way to bind any type of element? Or any generic view for same?
in my case i used this View view = findViewById(elementId); for binding but i got null.
Rather passing view id you should pass view in display method that is more convenient.
First Views Ids are generated automatically so if things you are storing this ids some Where and later used to get views it not right thing because Ids are generated and it different device to device and might change any time when application closed and start again.
You can do it by getIdentifier()
try {
String buttonID = elementId;//String name of id
int resID = getResources().getIdentifier(buttonID, "id", getPackageName());
View view = findViewById(resID);
if (isVisible) {
view.setVisibility(View.VISIBLE);
} else {
view.setVisibility(View.GONE);
} catch (Exception e) {
e.printStackTrace();
}
as above we are passing view id with combination of i and j values and then using getIdentifier() method to make Views objects .
I thing above code is solution towards your problem.
I would suggest using Kotlin instead of Java, and additionally using the core ktx library (it's a library of usefull Kotlin extensions for Android).
With it, you can do something like this:
view.isVisible = true sets the view to View.VISIBLE, whereas view.isVisible = false sets it to View.GONE
Similarly you have view.isInvisible which toggles between Invisible and Visible, and view.isGone which toggles between Gone and Visible.
In case you need the documentation of these methods, you can find it here.
Also, if you're using Kotlin instead of Java, you don't need to do findViewById(R.id.xxx), you can simply do a static import of any View.
The way app works is the following: App prompts 30 buttons to user and user may guess the right ones by tapping. When user taps some button all the buttons (say a view containing these buttons) should be locked while corresponding (right or wrong guess) animation is playing. Tapped button by itself should be disabled till the next round. After animation is finished all not tapped previously buttons (say a view containing these buttons) should be available again.
So I have a Layout which includes another layout with these 30 buttons:
...
<RelativeLayout
android:id="#+id/alphabetContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<include layout="#layout/alphabet" />
</RelativeLayout>
...
Now I need to lock the buttons from being clicked and then unlock. So I tried:
...
private RelativeLayout alphabetPanel;
...
public void onCreate(){
...
alphabetPanel = (RelativeLayout) findViewById(R.id.alphabetContainer);
...
}
...
private void lockButtons(){
alphabetPanel.setEnabled(false);
}
but this doesn't lock buttons. I also tried:
alphabetPanel.setFocusable(false);
alphabetPanel.setClickable(false);
Doesn't help either. Seems like it all relies only to a layout by itself but not the views it contains.
Also I tried to add a fake layout to place it over layout with buttons by bringing it to the front. This is a workaround and its tricky cuz both layouts must be placed inside a RelativeLayout only:
...
blockingLayout = new RelativeLayout(this);
blockingLayout.setLayoutParams(alphabetPanel.getLayoutParams());
...
but this works very strange: somehow both layouts in this case appears and disappears every second or so or doesn't appear at all - I cant understand that at all cuz there is no setVisibility() method used in code!
The only one way left is to iterate every view (button) to make it disabled and than back.
Is there any other way?
UPDATE
Finally I had to add a "wall"-layout into the xml. Now by making it clickable and focusable it becomes a solution.
Try setting for each Button's xml definition
android:duplicateParentState="true"
I'm not sure, but I think it should make them not only to seem disabled, but also to act accordingly.
Hmm it surprises me that disabling the parent-layout doesn't work.. as far as i know it should.
Try fetching your included layout instead, and disable that.
Anyway, if all else fails you can always loop through the buttons themselves.
for(int i=0;i<relativeLayout.getChildCount();i++){
View child=relativeLayout.getChildAt(i);
//your processing....
child.setEnabled(false);
}
I used extension to lock and unlock the view
//lock
fun View.lock() {
isEnabled = false
isClickable = false}
//unlock
fun View.unlock() {
isEnabled = true
isClickable = true}
if you want to lock all children of the view group
//lock children of the view group
fun ViewGroup.lockAllChildren() {
views().forEach { it.lock() }}
//unlock children of the view group
fun ViewGroup.unlockAllChildren() {
views().forEach { it.unlock() }}
firstly define your button
Button bit = (Button)findViewById(R.id.but);
bit.setEnabled(false);
and set enabled false;
Java:-
public void disableButtons(Layout layout) {
// Get all touchable views
ArrayList<View> layoutButtons = layout.getTouchables();
// loop through them, if they are instances of Button, disable them.
for(View v : layoutButtons){
if( v instanceof Button ) {
((Button)v).setEnabled(false);
}
}
}
Kotlin:-
fun disableButtons(layout: Layout) {
// Get all touchable views
val layoutButtons: ArrayList<View> = layout.getTouchables()
// loop through them, if they are instances of Button, disable them.
for (v in layoutButtons) {
if (v is Button) {
(v as Button).setEnabled(false)
}
}
}
Retrieve all touchables views into an ArrayList, then loop through them and check if it is an instance of the Button or TextView or which ever you want, then disable it!
In case data binding is needed
import android.view.ViewGroup
import android.widget.Button
import androidx.core.view.children
import androidx.databinding.BindingAdapter
#BindingAdapter("disableButtons")
fun ViewGroup.setDisableButtons(disableButtons: Boolean) {
children.forEach {
(it as? Button)?.isEnabled = !disableButtons
}
}
Usage:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="#dimen/guideline"
app:disableButtons="#{vm.busy}">
....
</androidx.constraintlayout.widget.ConstraintLayout>
Might work in constraint layout . Use group widget and add all the button ids.
In the java code set enabled false for the group.
For disable all buttons in any nested layouts.
void DisableAllButtons( ViewGroup viewGroup ){
for( int i = 0; i < viewGroup.getChildCount(); i++ ){
if( viewGroup.getChildAt(i) instanceof ViewGroup ){
DisableAllButtons( (ViewGroup) viewGroup.getChildAt(i) );
}else if( viewGroup.getChildAt(i) instanceof Button ){
viewGroup.getChildAt(i).setEnabled( false );
}
}
}
write these two lines on your button declartion in XML
android:setEnabled="false"
android:clickable="false"
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();
}
}