I wanna call mSearchView.clearFocus() when virtual keyboard is dismissed, how to do that?
My problem is once the SearchView gets focused, it keeps focused, so if I dismissed the virtual keyboard using back button, and I opened an AlertDialog - for example - the virtual keyboard pops up again once I close the AlertDialog as the search view still has the focus, as if it regains focus.
for the SearchView I used:
android:iconifiedByDefault="false"
android:focusable="false"
for the activity holds the SearchView I use:
android:windowSoftInputMode="stateUnspecified|adjustPan"
even if I changed it to the following I get the same problem
android:windowSoftInputMode="stateAlwaysHidden|adjustPan"
Eidt 1:
changing
android:iconifiedByDefault="false"
to be
android:iconifiedByDefault="true"
doesn't solve the problem, I get the same result.
Edit 2:
I tried the approach of creating a custom SearchView and to override onKeyPreIme and call clearFocus(), but onKeyPreIme doesn't get called.
public class ModifiedSearchView extends SearchView {
public ModifiedSearchView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onKeyPreIme (int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
clearFocus();
return false;
}
return super.dispatchKeyEvent(event);
}
}
To hide keyboard use this
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:focusableInTouchMode="true">
<SearchView
android:id="#+id/search_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:iconifiedByDefault="false"/>
</LinearLayout>
and then in you onBackPressed()
if (searchView != null) {
searchView.setQuery("", false);
searchView.clearFocus();
rootView.requestFocus();
}
while rootView is
rootView = findViewById(R.id.root_layout);
I have tried adding a searchview to a linerlayout and i do not have the same problem like you. But if you want to track virtual keyboard hide event use the following code in onCreate()
mLLWrapper.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Rect r = new Rect();
mLLWrapper.getWindowVisibleDisplayFrame(r);
int heightDiff = mLLWrapper.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 300) { // if more than 100 pixels, its probably
// keyboard visible
} else {
// keyboard in not visible
}
}
});
mLLWrapper is root LinearLayout view of activity
Once the keyboard is dismissed call clear focus. That might help. If not update your question with more code which will be easy for us to help you.
try this way
internal class ProductSearchView(context: Context, attrs: AttributeSet) : SearchView(context, attrs) {
override fun dispatchKeyEventPreIme(event: KeyEvent?): Boolean {
return false
}
}
Is an edittext cursor supposed to continue blinking after the soft keyboard is closed or is this a result of testing on an emulator and wouldn't happen on an actual device? -- as pointed out by the second post in this discussion
Update:
I know that the edittexts still have the cursor blinking because they're still in focus -- logged a message whenever edittext lost focus, but message was never logged when soft keyboard closed.
Update:
I've tried doing:
#Override
public void onBackPressed() {
super.onBackPressed();
getCurrentFocus().clearFocus();
}
So that every time the keyboard is closed, the EditText currently in focus loses that focus and onFocusChanged() is called. The problem is that onBackPressed() isn't called when the back button is pressed when the keyboard is up. I know this because I put a toast in onBackPressed(), and no toast shows when the back button is pressed whilst the keyboard is up.
First create a custom Edit text. Below is the example which has a call back when keyboard back is pressed to dismiss the keyboard
public class EdittextListner extends EditText {
private KeyImeChange keyImeChangeListener;
public EdittextListner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setKeyImeChangeListener(KeyImeChange listener) {
keyImeChangeListener = listener;
}
public interface KeyImeChange {
public boolean onKeyIme(int keyCode, KeyEvent event);
}
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyImeChangeListener != null) {
return keyImeChangeListener.onKeyIme(keyCode, event);
}
return false;
}
}
Secondly change your EditText to EdittextListner in you layout file.
Finally do the following
mLastNameEditText.setKeyImeChangeListener(new EdittextListner.KeyImeChange() {
#Override
public boolean onKeyIme(int keyCode, KeyEvent event) {
mLastNameEditText.clearFocus();
return true;
}
});
This worked for me. Hope this helps
Edittext is a View which accept input from user, so it is not related with keyborad open or close, when user will click on edittext, that edittext will get focus and cursor will start to blink for taking input,
So you can do one thing as when you are closing keyboard at the same time you can also set visibility of cursor for that edittext so it will stop to blink,
For that you need to write below line when you hide keyboard.
editTextObject.setCursorVisible(false);
This will stope cursor to blink.
As you said, the blinking cursor in the EditText is related to the EditText having focus, but showing or hiding the soft keyboard has no correlation to a View gaining or losing focus. Any View (EditText or otherwise) can be focused independent of whether or not a soft keyboard is showing and there is nothing intrinsic to EditText that would make it behave any differently.
If you want an EditText to lose focus whenever the soft keyboard is hidden, you will need to implement this functionality yourself by listening for changes in the soft keyboard visibility and updating the EditText as a result.
The only way to know keyboard is disappeared is to override
OnglobalLayout and check the height.
Based on that event you can "setCursorVisible(false)" on your edit text
For more information, check this Link.
RelativeLayout mainLayout = findViewById(R.layout.main_layout); // You must use the layout root
InputMethodManager im = (InputMethodManager) getSystemService(Service.INPUT_METHOD_SERVICE);
/*
Instantiate and pass a callback
*/
SoftKeyboard softKeyboard;
softKeyboard = new SoftKeyboard(mainLayout, im);
softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged()
{
#Override
public void onSoftKeyboardHide()
{
// Code here
EditText.clearFocus();
}
#Override
public void onSoftKeyboardShow()
{
// Code here
}
});
/*
Open or close the soft keyboard easily
*/
softKeyboard.openSoftKeyboard();
softKeyboard.closeSoftKeyboard();
/* Prevent memory leaks:
*/
#Override
public void onDestroy()
{
super.onDestroy();
softKeyboard.unRegisterSoftKeyboardCallback();
}
try this:
public class EditTextBackEvent extends EditText {
private EditTextImeBackListener mOnImeBack;
public EditTextBackEvent(Context context) {
super(context);
}
public EditTextBackEvent(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EditTextBackEvent(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
if (mOnImeBack != null) mOnImeBack.onImeBack(this, this.getText().toString());
}
return super.dispatchKeyEvent(event);
}
public void setOnEditTextImeBackListener(EditTextImeBackListener listener) {
mOnImeBack = listener;
}
public interface EditTextImeBackListener {
void onImeBack(EditTextBackEvent ctrl, String text);
}
}
in your layout:
<yourpackagename.EditTextBackEvent
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
and in your fragment:
edittext.setOnEditTextImeBackListener(new EditTextBackEvent.EditTextImeBackListener()
{
#Override
public void onImeBack(EditTextBackEvent ctrl, String text)
{
edittext.clearfocus();
}
});
Try keeping a view in your layout which is focusable above your editText.
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:focusable="true"
android:focusableInTouchMode="true" />
This should work as the blank focusable view should catch focus and not your edittext.
I have a custom dialog which is a DialogFragment. This dialog have a EditText and my own keyboard view so I don't want to use the default virtual keyboard.
I hide the virtual keyboard everytime user touch the EditText:
edtAmount.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
v.onTouchEvent(event);
View view = this.getDialog().getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager) getActivity()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(),0);
}
return true;
}
});
But because the system still call the virtual keyboard to show (Before is force to hide it), then system move my dialog up and down very quickly. This is not good.
Can someone help me to avoid the dialog pushed up like this, just keep it stay still?
PS: I tried in Manifest:
android:windowSoftInputMode="adjustNothing"
But seem like not work.
Thank you very much.
EDIT
I want to keep the cursor so I find the solution in this thread:
https://stackoverflow.com/a/14184958/2961402
Hope this help some one.
This can only done when you extends the EditText from your custom EditText, please use the below code for custom EditText which never open Soft Keyboard ever...!
public class DisableSoftKeyBoardEditText extends EditText {
public DisableSoftKeyBoardEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onCheckIsTextEditor() {
return false;
}
}
Try this code. In my app it work perfectly
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
When using AutoCompleteTextView, the dropdown suggestion list appears with the software keyboard still visible. This makes sense, as it is often a lot more efficient to type ensuing characters to narrow the list.
But if the user wants to navigate the suggestion list, it becomes extremely tedious with the software keyboard still up (this is even more of a problem when the device is in landscape orientation). Navigating the list is a lot easier without the keyboard hogging the screen space. Unfortunately, the default behaviour removes the list first when you press the back key (even though in the software versions of the back key it is showing the image that says 'pressing this will hide the keyboard').
Here's a barebones example that demonstrates what I'm talking about:
public class Main2 extends Activity {
private static final String[] items = {
"One",
"Two",
"Three",
"Four",
"Five"
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AutoCompleteTextView actv = new AutoCompleteTextView(this);
actv.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
actv.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items));
actv.setThreshold(1);
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
ll.addView(actv);
setContentView(ll);
}
}
Besides the fact that this is unintuitive (the back key hint is suggesting that the back press will be sent to the keyboard), it makes navigating AutoCompleteTextView suggestions extremely tiresome.
What is the least intrusive way (e.g. catching the back in on onBackPressed() in every activity and routing it accordingly would definitely not be ideal) to make the first back press hide the keyboard, and the second remove the suggestion list?
You can achieve that by override-ing onKeyPreIme in your custom AutoCompleteTextView.
public class CustomAutoCompleteTextView extends AutoCompleteTextView {
public CustomAutoCompleteTextView(Context context) {
super(context);
}
public CustomAutoCompleteTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && isPopupShowing()) {
InputMethodManager inputManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (inputManager.hideSoftInputFromWindow(findFocus().getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS)) {
return true;
}
}
return super.onKeyPreIme(keyCode, event);
}
}
set DismissClickListener like this
autoCompleteTextView.setOnDismissListener(new AutoCompleteTextView.OnDismissListener() {
#Override
public void onDismiss() {
InputMethodManager in = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
in.hideSoftInputFromWindow(getCurrentFocus().getApplicationWindowToken(), 0);
}
});
Seems to be a common problem without a great solution that I have found. Goal is to stop a ScrollView from auto-scrolling to an EditText (or any view for that matter) that has focus.
You have a bunch of views (Buttons, TextViews, etc) in an ScrollView, one of which is an EditText. Upon clicking say a Button within the ScrollView, the ScrollView scrolls down to the EditText (its off screen). This is not desired, as there are other elements that you don't want scrolled off the screen.
Now I can stop this from happening when the screen first shows by having other focusable elements in the ScrollView. However, the general problem still exists. The user scrolls down manually to the EditText, enters some numbers, then scrolls up to the top (EditText off screen now), they click a button in the ScrollView, and guess what? The ScrollView scrolls down to that darn EditText.
I'm thinking about extending the ScrollView and overriding some of the methods there like findFocusableViewInBounds, but I have a feeling I'll just be getting myself into more trouble.
Please help if you can.
I've played around with things like having an 0 height EditText at the top of my ScrollView, adding Next Focusable element properties to the other items in the ScrollView, etc. I suppose one "hack" might be to get the EditText to lose focus when the virtual or manual keyboard gets hidden or something.
After struggling with that problem for quite some time, I've found a solution that seems to work without being too ugly. First, make sure that whatever ViewGroup (directly) contains your EditText has descendantFocusability set to "Before Descendants," focusable set to "true" and focusableInTouchMode set to "true." This will not be the ScrollView itself, but the layout inside where you have your various views. Next add an onTouchListener to your ScrollView that removes focus from the EditText whenever it is touched, like so:
ScrollView scroll = (ScrollView)findViewById(R.id.scrollView1);
scroll.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (myEditText.hasFocus()) {
myEditText.clearFocus();
}
return false;
}
});
Tell me if that doesn't fix it. What should happen is that the Layout gets focus instead of the EditText, so no scrolling should happen.
Just create an empty view at the top of linearlayout
<View android:layout_width="fill_parent" android:id="#+id/focus_view" android:layout_height="0dp" android:focusable="true" android:focusableInTouchMode="true"><requestFocus/></View>
Single line solves the problem
I had the same problem. There's one trick that I'm using to deal with this problem:
public void onClick(View v) {
button.requestFocusFromTouch(); //prevents from loosing focus and scrolling view down
....
}
The issue is not on the java code, but on the manifest code.
In your AndroidManifest.xml add an attribute to the Activity:
<activity android:name=".MyActivity" android:windowSoftInputMode="adjustPan"> </activity>
By adding 2 parameters in:
android:focusable="true"
android:focusableInTouchMode="true"
In which Main layout is there.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/layMain"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background"
android:focusable="true"
android:focusableInTouchMode="true">
By this EditText will not be auto focused.
Here is what I did
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" style="#style/measurementTableRowStyle"
android:focusable="true" android:layout_height="fill_parent">
<requestFocus></requestFocus>
<LinearLayout android:id="#+id/linearLayout1"
android:orientation="horizontal" android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:id="#+id/desc_text" android:text="Value : "
style="#style/attributeNameTextStyle" android:layout_width="wrap_content"
android:focusable="true" android:layout_height="wrap_content">
<requestFocus></requestFocus>
</TextView>
<TextView style="#style/attributeValueStyle" android:id="#+id/value_text"
android:text="TextView" android:layout_width="wrap_content"
android:layout_height="wrap_content"></TextView>
</LinearLayout>
The reason is in such cases you have to make all other views focus-able inside the scrollview by an explicit android:focusable="true" and then <requestFocus></requestFocus> . This should work everytime IMO
thomas88wp answer, https://stackoverflow.com/a/6486348/528746 worked for me.
But I had two problems:
1. When scrolling, I wanted to hide the keyboard
2. I had lots of EditText views and didn't want to write it for each one of them
(I do getActivity() since I'm writing this inside a Fragment and not an activity)
ScrollView scroll = (ScrollView)view.findViewById(R.id.layout_scroll);
scroll.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// Check if the view with focus is EditText
if (getActivity().getCurrentFocus() instanceof EditText)
{
EditText ed = (EditText)getActivity().getCurrentFocus();
if (ed.hasFocus()) {
// Hide the keyboard
InputMethodManager inputManager = (InputMethodManager)
getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
// Clear the focus
ed.clearFocus();
}
}
return false;
}
});
My fix to this most horrific bug, (worth noting that this is pre API11 only where they modified the fling method not to be stupid).
The old fling method finds the next focus that it will get to.. which isn't really that helpful. Other versions of this class don't really work as they stop focus working when the user genuinely traverses the form from the keyboard.
public class NonFocusingScrollView extends ScrollView {
private boolean mBlockRequestFocusOnFling = false;
public NonFocusingScrollView(Context context) {
super(context);
}
public NonFocusingScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NonFocusingScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public ArrayList<View> getFocusables(int direction) {
if(mBlockRequestFocusOnFling)
return new ArrayList<View>();
return super.getFocusables(direction);
}
#Override
public void requestChildFocus(View child, View focused) {
if(!mBlockRequestFocusOnFling)
super.requestChildFocus(child, focused);
}
#Override
public void fling(int velocityY) {
mBlockRequestFocusOnFling = true;
super.fling(velocityY);
mBlockRequestFocusOnFling = false;
}
}
I was having a similar problem and finally got it to work. My scroll view contains a series of customized buttons, followed by an EditText (which normally has focus, but I don't want it to be losing focus). Any time the buttons were clicked, the scroll view auto-scrolled to the focused EditText. Overriding public boolean requestChildRectangleOnScreen(final View child, final Rect rectangle, final boolean immediate) and always returning false (default behavior of a ViewGroup) did the trick. Hope it helps with your situation too.
We can write a custom ScrollView and override the onScrollChanged method and clear the focus from the focused view and optionally hide the keyboard.
#Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
View v = getFocusedChild();
if (v != null) {
InputMethodManager imm = (InputMethodManager) getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
v.clearFocus();
}
super.onScrollChanged(l, t, oldl, oldt);
}
I often has this problem when my apps handle orientation change.
In that case I use the following kind of code:
#Override
protected void onCreate(Bundle savedInstanceState) {
...
// to avoid the scrollview to scroll to this element automatically
mEditTextSearch.setFocusable(false);
// Get the saved scroll position
final int scrolly = savedInstanceState.getInt("scrolly");
mScrollView.post(new Runnable() {
#Override
public void run() {
mScrollView.scrollTo(0, scrolly);
// Restore the initial state of the EditText
mEditTextSearch.setFocusable(true);
mEditTextSearch.setFocusableInTouchMode(true);
mEditTextSearch.setClickable(true);
}
});
...
}
Another version of thomas88wp's code:
ScrollView scroll = (ScrollView)getActivity().findViewById(R.id.scrollView_addNewBill);
scroll.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
View focussedView = getCurrentFocus();
if( focussedView != null ) focussedView.clearFocus();
return false;
}
});
I made a test project to experiment with the various solutions if anyone wants to play with it.
https://github.com/marchold/EditText-ErrorPopup-Scroll-View
Create a custom ScrollView (create a class and have it extend HorizontalScrollView) and make a getter setter for scrollable. Then override computeScrollDeltaToGetChildRectOnScreen.
How it works: Every time android has an edit text or something in focus that is off screen it calls method computeScrollDeltaToGetChildRectOnScreen to bring it into view. If you Override it and return 0 when it is disabled than it will not scroll...
So you will have A custom scroll view like this:
public class TrackableHorizontalScrollView extends HorizontalScrollView {
// true if we can scroll (not locked)
// false if we cannot scroll (locked)
private boolean mScrollable = true;
public TrackableHorizontalScrollView(Context context) {
super(context);
}
public TrackableHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TrackableHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setScrollingEnabled(boolean enabled) {
mScrollable = enabled;
}
public boolean isScrollable() {
return mScrollable;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// if we can scroll pass the event to the superclass
if (mScrollable) return super.onTouchEvent(ev);
// only continue to handle the touch event if scrolling enabled
return mScrollable; // mScrollable is always false at this point
default:
return super.onTouchEvent(ev);
}
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Don't do anything with intercepted touch events if
// we are not scrollable
if (!mScrollable) return false;
else return super.onInterceptTouchEvent(ev);
}
#Override
public void scrollTo(int x, int y){
if (!mScrollable) return;
super.scrollTo(x, y);
}
//Custom smooth scroll method since norm is final and cannot be overridden
public final void smooothScrollToIfEnabled(int x, int y){
if (!mScrollable) return;
smoothScrollTo(x, y);
}
#Override
protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect rect){
if (!mScrollable) return 0;
return super.computeScrollDeltaToGetChildRectOnScreen(rect);
}
}
You can use this inside your XML like this:
<com.your.package.ui.widget.TrackableHorizontalScrollView
android:id="#+id/wi_et_credit_scroller"
android:layout_toRightOf="#id/wi_et_credit_iv"
android:layout_width="fill_parent"
android:scrollbars="none"
android:layout_height="wrap_content"
android:paddingRight="5dp"
android:layout_gravity="center_vertical">
<!--Whatever you have inside the scrollview-->
</com.your.package.ui.widget.TrackableHorizontalScrollView>
The best Solution is to add focus options for the child of your scrollview :
android:descendantFocusability="beforeDescendants"
android:focusable="true"
android:focusableInTouchMode="true"
Then your xml file will look like :
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginRight="50dp"
android:descendantFocusability="beforeDescendants"
android:focusable="true"
android:focusableInTouchMode="true"
android:orientation="vertical" >
<EditText
android:id="#+id/editText_one"
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="TestApp 1" />
<EditText
android:id="#+id/editText_two"
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="TestApp 2" />
<EditText
android:id="#+id/editText_three"
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="TestApp 3" />
</LinearLayout>
</ScrollView>
For me, it didn't work to override ScrollView onTouch. Also did not work android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="true"
This and another mentioned solutions only worked for the first time - only when EditText is not selected, but once you select it, scrollview autoscrolls again.
Because I was already written a code to hide a keyboard when touching other views, I just added two lines of code and it worked like a champ:
public static void setupUI(final Activity activity, final View view) {
//view is the parent view in your layout
OnTouchListener mTouchListener = new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
try {
View vFocused = null;
vFocused = activity.getCurrentFocus();
if (vFocused != null) {
hideSoftKeyboard(activity, v);
if (vFocused instanceof EditText) {
vFocused.clearFocus();//this is the trick to avoid ScrollView autoscroll
}
}
} catch (Exception e) {
}
return false;
}
};
// Set up touch listener for non-text box views to hide keyboard.
if (!(view instanceof EditText) && !(view instanceof ViewGroup)) {
view.setOnTouchListener(mTouchListener);
}
// If a layout container, iterate over children and seed recursion.
if (view instanceof ViewGroup) {
view.setOnTouchListener(mTouchListener);
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
View innerView = ((ViewGroup) view).getChildAt(i);
setupUI(activity, innerView);
}
}
}
public static void hideSoftKeyboard(Context context, View v) {
InputMethodManager inputMethodManager = (InputMethodManager) context
.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
also added this in root view:
android:descendantFocusability="beforeDescendants" android:focusableInTouchMode="true"
Maybe its not really nice solution, but its working.
My solution is below, to trace the source code and override some function to stop auto scrolling by focused item.
You can check if the focusedView is TextView or its child is TextView,
by using focusedView.findViewById(R.id.textview_id_you_defined) != null or focusedView instanceof TextView == true.
public class StopAutoFocusScrollView extends ScrollView {
private View focusedView;
private ScrollMonitorListener listener;
public interface ScrollMonitorListener {
public boolean enableScroll(View view);
}
public StopAutoFocusScrollView(Context context) {
super(context);
}
public StopAutoFocusScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public StopAutoFocusScrollView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public void setScrollMonitorListener(ScrollMonitorListener listener) {
this.listener = listener;
}
#Override
public void requestChildFocus(View child, View focused) {
focusedView = focused
super.requestChildFocus(child, focused);
}
//flow : requestChildFocus -> scrollToChild -> scrollBy
//Therefore, you can give listener to determine you want scroll to or not
#Override
public void scrollBy(int x, int y) {
if (listener == null || listener.enableScroll(focusedView)) {
super.scrollBy(x, y);
}
}
}
I had a slightly different objection to this infuriating deficiency. Whenever I tapped one of a number of RadioButtons below the EditTexts, the scroll position jumped to accommodate what Android determined to be the visible and focused EditText.
All attempts to retain the current desired scroll position via a Runnable that issued ScrollView.scrollTo(x,y) were dutifully IGNORED by Android!
I share my solution in the hope that it may save someone else 8 (eight) wasted hours.
/* This interesting little 'hack' prevents unwanted scroll 'jump' occurring when
user touches a RadioButton for example
[ Causes focus to change - but maybe this is a lesser evil! ] */
mScrollView.setOnTouchListener(new View.OnTouchListener() {
#Override public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_UP)
return false;
mScrollView.clearFocus();
return false;
}
});
Only this code works for me:
public static void preventScrollViewFromScrollingToEdiText(ScrollView view) {
view.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
view.setFocusable(true);
view.setFocusableInTouchMode(true);
view.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
v.requestFocusFromTouch();
return false;
}
});
}
All credits go to this original answer.
Try this one :)
public class CustomHorizontalScrollView extends HorizontalScrollView {
public CustomHorizontalScrollView(Context context) {
super(context);
}
public CustomHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(ev);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev);
}
#Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
}
//Custom smooth scroll method since norm is final and cannot be overridden
public final void smooothScrollToIfEnabled(int x, int y) {
smoothScrollTo(x, y);
}
#Override
protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect rect) {
/* if (getContext() != null && getContext() instanceof Activity) {
Activity activity = (Activity) getContext();
if (!activity.isFinishing()) {
View view = activity.getCurrentFocus();
if (view != null) {
if (view instanceof EditText) {
return 0;
}
}
}
}
return super.computeScrollDeltaToGetChildRectOnScreen(rect);
*/
return 0;
}
}
I solved this problem adding the descendantFocusability attribute to the ScrollView's containing LinearLayout, with the value blocksDescendants.
For example:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:descendantFocusability="blocksDescendants" >
None of these answers worked for me.
What I did was, I added: android:overScrollMode="never" in my ScrollView and set the height to wrap_content.
My view was very complex as it was legacy code with LinearLayout inside LinearLayout inside LinearLayout.
This helped me, hope it will help someone else too!