AutoCompleteTextView always keeps focus - android

I have 2 AutoCompleteTextViews in an activity (LinearLayout) and several additional controls (radiogroups, buttons, etc). Somehow the AutoCompleteTextViews are never losing focus.
As Example:
The user clicks on an AutoCompleteTextView, the control gets the focus. So the cursor starts blinking, the autocomplete dropdown list and the keyboard is shown. This is fine.
However if the user now clicks on of the radio buttons (or another control), the cursor in the AutoCompleteTextView is still blinking and the keyboard is still shown.
How to make the focus disappear automatically?
EDIT: xml code
<AutoCompleteTextView
android:id="#+id/ediFrom"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:text="" />

Only solution that worked for me is to add this line
android:focusable="true"
android:focusableInTouchMode="true"
To parent of AutoCompleteTextView (like LinearLayout etc..)

have u tried with android:focusableInTouchMode="true" for each view
code snippet
<AutoCompleteTextView
android:id="#+id/ediFrom"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:focusableInTouchMode="true"
android:text="" />
http://android-developers.blogspot.in/2008/12/touch-mode.html

In order to avoid setting everything else focusable (which is painful if you happen to use the same text view in many other layouts), we opt to override the logic to intercept touch screen events at activity level instead:
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
View v = getCurrentFocus();
if (v instanceof EditText) {
int scrcoords[] = new int[2];
v.getLocationOnScreen(scrcoords);
// calculate the relative position of the clicking position against the position of the view
float x = event.getRawX() - scrcoords[0];
float y = event.getRawY() - scrcoords[1];
// check whether action is up and the clicking position is outside of the view
if (event.getAction() == MotionEvent.ACTION_UP
&& (x < 0 || x > v.getRight() - v.getLeft()
|| y < 0 || y > v.getBottom() - v.getTop())) {
if (v.getOnFocusChangeListener() != null) {
v.getOnFocusChangeListener().onFocusChange(v, false);
}
}
}
return super.dispatchTouchEvent(event);
}
If you put this logic in your base activity, any screen with an edit text now will fire onFocusChange when you tap anywhere outside it. By listening to onFocusChange you can clearFocus or requestFocus on another view. It's a hack more or less but at least you don't have to set focusable for any other items on many layouts.
See http://developer.android.com/reference/android/app/Activity.html#dispatchTouchEvent(android.view.MotionEvent)

You can use the method setOnDismissListener() to clear the focus whenever the dropdown is dismissed (value picked, clicked outside)
This Kotlin code works fine for me, you can easily rewrite it to java too:
materialAutoCompleteTextBox.setOnDismissListener {
materialAutoCompleteTextBox.clearFocus()
}

Related

listview android scroll on some devices and doesn't scroll on the other

listview scroll on some devices Nexus_5x and doesn't scroll on Samsung galaxy tab 7
I try everything on the internet :
this doesn't work !
// save index and top position
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : (v.getTop() - mList.getPaddingTop());
// ...
// restore index and position
mList.setSelectionFromTop(index, top);
Link here
Maintain/Save/Restore scroll position when returning to a ListView
also this doesn't work
ListView lv = (ListView)findViewById(R.id.myListView); // your listview inside scrollview
lv.setOnTouchListener(new ListView.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// Disallow ScrollView to intercept touch events.
v.getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
// Allow ScrollView to intercept touch events.
v.getParent().requestDisallowInterceptTouchEvent(false);
break;
}
// Handle ListView touch events.
v.onTouchEvent(event);
return true;
}
});
link here
ListView inside ScrollView is not scrolling on Android
My listView xml is
<ListView
android:id="#+id/listview"
style="#style/ListView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginEnd="5dp"
android:layout_marginStart="5dp"
android:layout_marginTop="8dp"
android:visibility="visible"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/buttonClear"
tools:layout_constraintLeft_creator="1"
tools:layout_constraintRight_creator="1"
tools:layout_constraintTop_creator="1" />
landscape doesn't work , but portrait is just fine.
I don't understand why it's ok on some devices and even portrait mode but not the other ?
To start with, its not always a good idea to nest a scrollable view in another especially when they are scrolling in the same direction, although in some cases there are not much alternatives. When I want to implement something like that say a recyclerview in a scrollview, I disable the scrolling behaviour of the recyclerview and make the size expand depending on the size of the contents
http://www.it1me.com/it-answers?id=33330388&ttl=How+to+put+RecyclerView+inside+NestedScrollView%3F
That is a link to where it is implemented. Study it so you'll get the idea.
Goodluck

android - show keyboard fix bottom framelayout

I am developing an android application in which my mainActivity has 5 tabs at the bottom represented in FrameLayout. Each tab points to a particular fragment which gets loaded based on the tab clicked.
In my 1st tab, I've an EditText. When the edit text is focused, I need to show the keyboard by just moving the layout of ('EditText and Send button) "up" without pushing up the other components including the bottom tab frame layout. Similarly when hiding the keyboard, the 'EditText and Send btn' layout should sit just above the tab frame layout. Can someone please suggest me the solution for this?
(Assume the situation same as in Facebook comment. When we go inside a post to comment something, the layout ('Write Comment' ET and POST btn) will be pushed up without moving any other components including the bottom tabs ('News Feed', 'Requests', 'Messenger', 'Notifications', 'More'))
I don't want to make the frame layout Visibility.Gone/Visible as it ends up in an ugly animation when the keyboard slides up/down.
Use a LinearLayout whit no weightSum, and give your main View in your layout 0dp height, and weight 1
I have the exact same issue. The best workaround I could find (as alluded to in the original question) is below. But this is a marginal solution, and not a great one.
The problem with setting the weightSum is that if the scrollview containing the edit boxes is longer, the button will disappear. The best solution would allow the buttons to stay at bottom of page on normal view, but to be hidden during keyboard onscreen.
public boolean dispatchTouchEvent(MotionEvent event) {
View v = getCurrentFocus();
boolean ret = super.dispatchTouchEvent(event);
if (v instanceof EditText) {
View w = getCurrentFocus();
int scrcoords[] = new int[2];
w.getLocationOnScreen(scrcoords);
float x = event.getRawX() + w.getLeft() - scrcoords[0];
float y = event.getRawY() + w.getTop() - scrcoords[1];
if (event.getAction() == MotionEvent.ACTION_UP && (x < w.getLeft() || x >= w.getRight() || y < w.getTop() || y > w.getBottom()) ) {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getWindow().getCurrentFocus().getWindowToken(), 0);
layButton.setVisibility(View.VISIBLE);
}
else
{
layButton.setVisibility(View.GONE);
}
}
return ret;
}

Android No Touch Events after Translating Canvas

I have scoured the web in search of an answer to a question that has been bugging me for days. I am making a widget that allows a user to pan the entire widget by dragging (around the Y axis only) within the viewing area. I then have a smaller view (like a button, listens to onTouchEvent) inside here that the user can also drag. The idea is that the user will drag this view up or down and if they want to go higher or lower they can pan the entire widget and then continue dragging the view higher or lower. Now, I'm having two issues with this. First off, after dragging the main view (whole widget) the view that I would like to then move still resides in the area it once was before translating the entire canvas.
So for example, if I move the entire canvas by 50 in the Y position, I then want to move the smaller view but have to touch in the old position rather than the offsetted one (by 50). So it looks like I don't click the smaller view where it is now, but where it used to be (I hope this makes sense).
Next issue, after I move the smaller view. I am not able to trigger anymore touch events. I'm assuming that's because it was moved outside of its parent (which is still viewable since I set clipChildren to false) and its "z-order" is lower than the other views in the layout. Is there a way to always position this on top? I am using Android API 17. Even if I set this smaller view (that I am moving when touched and ACTION_MOVE event is triggered) as the last child in the main layout, I need to be able to drag it out of here (which I can) and continue to drag it on a new onTouchEvent. ANY help is greatly appreciated. I added some layout xml and code snippets below to help.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false">
<RelativeLayout
android:id="#+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:clipChildren="false"
android:clipToPadding="false">
<ImageView
android:id="#+id/ref_image"
android:layout_width="wrap_content"
android:layout_height="216dp"
android:src="#drawable/my_ref_image"
android:layout_centerInParent="true"
android:clipChildren="false"/>
<RelativeLayout
android:id="#+id/selection_view"
style="#style/MyStyle"
android:layout_alignTop="#id/ref_image"
android:layout_marginTop="116dp"
android:clipChildren="false"
android:clipToPadding="false">
<RelativeLayout
android:id="#+id/selection_area"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:clipChildren="false"
android:clipToPadding="false">
<ImageView
android:id="#+id/underlay_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/translucent_image"
android:layout_centerInParent="true"/>
<ImageView
android:id="#+id/point_area"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/point_image"
android:layout_centerInParent="true"/>
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
So the snippets of code that is of interest:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (DEBUG) {
Log.d(TAG, TAG + "::onDraw: ");
}
canvas.translate(0, backgroundPositionY);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
Log.d(TAG, TAG + "::onTouchEvent: parent touch event");
switch (action) {
case MotionEvent.ACTION_DOWN: {
final float y = ev.getY();
// Remember where we started
lastTouchY = y;
if (DEBUG) {
Log.d(TAG, TAG + "::onTouchEvent: parent ACTION_DOWN");
}
return true;
}
case MotionEvent.ACTION_MOVE: {
final float y = ev.getY();
// Calculate the distance moved
final float dy = y - lastTouchY;
backgroundPositionY += dy
// Remember this touch position for the next move event
lastTouchY = y;
// Invalidate to request a redraw
invalidate();
break;
}
case MotionEvent.ACTION_UP: {
lastTouchY = ev.getY();
}
}
return false;
}
// called upon initialization (selectionArea refs view id = selection_area)
private void initPointListener() {
this.setClipChildren(false);
this.setClipToPadding(false);
if (selectionArea != null) {
selectionArea .setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
RelativeLayout.LayoutParams pointParams = (RelativeLayout.LayoutParams) selectionArea.getLayoutParams();
final int action = motionEvent.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN: {
pointLastTouchY = motionEvent.getY();
}
break;
}
case MotionEvent.ACTION_MOVE: {
float moveY = motionEvent.getY();
final float dy = moveY - pointLastTouchY;
pointPosY += dy;
selectionArea.setY(pointPosY);
break;
}
}
return true;
}
});
}
}
Note that I have tried setting the padding and I have referenced the following on SO with no good results:
How to translate the canvas and still get the touch events on the correct places
Android : click / touch event not working after canvas translate
Alright, well... I found a work around. Basically, my parent view (the widget itself) could always see touch events. But the children could not given the circumstances I mentioned above. So, what I did was keep track of the x and y positions of the child view I was dragging relative to the viewing area. Then whenever I received a touch event I would check to see if I touched the child area or not. If I happened to trigger the onTouchEvent for the child when it was in its old location, I would ignore it if it didn't pass this check. Its sloppy, but its the only way I could get it to work. Now I have a pannable view and a draggable object
I'm not sure did I understand everything on your problem right but maybe this could help you
View with horizontal and vertical pan/drag and pinch-zoom You should try the code from Alex's answer. The code is doing some extra things but you could just take scalelistener (for zoom) off and ofcourse the panning for X-axis. That code is also moving childviews "inside" the canvas so then you shouldn't have to translate click positions after onTouch called.
The better solution is the leave your view in place. Then apply a matrix transformation to your view and the inverted matrix to MotionEvents. This way you can always get your view properly and klugelessly delegated your events, and all the panning takes place in the drawing of the scene. Moving the view around will also hit a basically unpassable problem that you cannot get the MotionEvents that start outside of the bounds of your real view. So if you zoom out, and press something outside the the area where the screen would be it ignores that and doesn't dispatch the touch events there.
Also, it goes insane on some implementations, I think galaxy tab 10, it was just horribly fubar and impossible wrong. It does the invalidation of the view a bit differently than other tablets and refreshed the wrong parts of the view.

Frame layout getting stuck when I hide soft input (Android)

I have an Android app (fullscreen, landscape), and I have two Views, one is a FrameLayout that's always visible, and one's a LinearLayout. I set the visibility on the LinearLayout to View.GONE right off the bat. When the user taps a button on the FrameLayout, I set visibility on the LinearLayout to view.VISIBLE, and use the InputMethodManager to show the soft input on an EditText in the LinearLayout. This results in both views being shifted up such that the EditText is on screen just above the keyboard. This is all fine.
The problem arises when I close the soft input. In the same callback, I set the visibility of the LinearLayout (with the EditText) to View.GONE, and what I'm seeing is the FrameLayout getting stuck on top of the screen (it doesn't shift back down). If I don't GONE-ize the LinearLayout, both Views shift back down just fine.
I can work around the issue by starting a timer to wait before setting the visibility to GONE, but I shouldn't have to do that; there should be some notification that I can receive consistently that will indicate when I can hide the LinearLayout.
Things I've tried: hideSoftInputFromWindow with a ResultReceiver (result receiver callback gets invoked pretty well immediately (i.e. before the keyboard actually disappears), view is GONEd too quickly, same problem), overriding onLayout for the LinearLayout (doesn't get invoked when the soft input moves the View up and down), overriding other View "on"s.
The other really annoying thing is this problem seems to be exclusive to my phone - an AT&T Samsung Galaxy SII Skyrocket running Android 4.0.4 (possibly with some Samsung modifications). I can't repro on a 4.0.3 simulator, nor can anyone else repro on other devices with other Android versions.
Any ideas?
You're going to have to write your own touch event handler. Here is an example that will slide the whole frameLayout view down when the soft input is hidden. As you can see, it is important to call the super handler and wrap our code in a test for textEdit widgets. If you want to get a look at the calculations, uncomment the debugging logger code.
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
View v = getCurrentFocus();
boolean ret = super.dispatchTouchEvent(event);
if (v instanceof EditText) {
View w = getCurrentFocus();
int scrcoords[] = new int[2];
w.getLocationOnScreen(scrcoords);
float x = event.getRawX() + w.getLeft() - scrcoords[0];
float y = event.getRawY() + w.getTop() - scrcoords[1];
// Log.d("Activity",
// "Touch event "+event.getRawX()+","+event.getRawY()+" "+x+","+y+" rect "+w.getLeft()+","+w.getTop()+","+w.getRight()+","+w.getBottom()+" coords "+scrcoords[0]+","+scrcoords[1]);
if (event.getAction() == MotionEvent.ACTION_UP
&& (x < w.getLeft() || x >= w.getRight() || y < w.getTop() || y > w
.getBottom())) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getWindow().getCurrentFocus()
.getWindowToken(), 0);
}
}
return ret;
}

Implement onClick only for a TextView compound drawable

I need to have some text with a drawable on the left and I want to execute some code when the user clicks/touches the image (only the image, not the text), so I used a LinearLayout with a TextView and an ImageView which is clickable and launches an onClick event. The XML parser suggests me to replace this with a TextView with a compound drawable, which would draw the same thing with far less lines of XML.. My question is "can I specify I want to handle an onClick event only on the drawable of the TextView and not on the TextView itself? I've seen some solutions which involves writing your own extension of TextView, but I'm only interested in being able to do it within the layout resource, if possible, otherwise I'll keep the following XML code:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="bottom"
android:paddingTop="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="#string/home_feedback_title"
android:textColor="#android:color/primary_text_dark"
android:textStyle="bold"
android:paddingBottom="4dp"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/action_feedback"
android:clickable="true"
android:onClick="onClickFeedback"
android:contentDescription="#string/action_feedback_description"/>
</LinearLayout>
Its very simple. Lets say you have a drawable on left side of your TextView 'txtview'. Following will do the trick.
TextView txtview = (TextView) findViewById(R.id.txtview);
txtview.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP) {
if(event.getRawX() <= txtview.getTotalPaddingLeft()) {
// your action for drawable click event
return true;
}
}
return true;
}
});
If you want for right drawable change the if statement to:
if(event.getRawX() >= txtview.getRight() - txtview.getTotalPaddingRight())
Similarly, you can do it for all compound drawables.
txtview.getTotalPaddingTop();
txtview.getTotalPaddingBottom();
This method call returns all the padding on that side including any drawables. You can use this even for TextView, Button etc.
Click here for reference from android developer site.
You can go either way. Using the compound drawable is faster though because it was intended to be an optimization. It uses less ram because you reduce 3 views into 1 and it's faster layout because you lose 1 depth.
If I were you I'd consider stepping back to see if both the text and the image intercepting the touch to do whatever action is possibly a good thing. In general having a larger touch region makes it easier to press. Some users may actually be inclined to touch the text instead of the image.
Lastly if you go that route of merging the 2 you might want to consider using a Button instead of a TextView. You can style the button to not have the rectangle around it. They call it a borderless button. It's nice because you get visual feedback that you clicked on a actionable item where as an ImageView or TextView normally aren't actionable.
How to Create Borderless Buttons in Android
#Vishnuvathsan's answer is almost perfect, but getRaw() returns an absolute x position of the touch point. If the textview is located not on the left edge of the view, you should compare with the absolute position of the textview by using getLocationOnScreen. Code below is an example to check both left drawable tap and right drawable tap.
textView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
int[] textLocation = new int[2];
textView.getLocationOnScreen(textLocation);
if (event.getRawX() <= textLocation[0] + textView.getTotalPaddingLeft()) {
// Left drawable was tapped
return true;
}
if (event.getRawX() >= textLocation[0] + textView.getWidth() - textView.getTotalPaddingRight()){
// Right drawable was tapped
return true;
}
}
return true;
}
});
final int DRAWABLE_LEFT = 0;
final int DRAWABLE_TOP = 1;
final int DRAWABLE_RIGHT = 2;
final int DRAWABLE_DOWN = 3;
This click listener is getting in on touch listener
if (event.getAction() == MotionEvent.ACTION_DOWN)
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (event.getX() >= (tvFollow.getTop() - tvFollow.getCompoundDrawables()[DRAWABLE_TOP].getBounds().width())) {
// your action here
return true; } }
Since getRaw() and getRight() both returns in regards with the entire screen coordinates, this will not work if your views are not on the left edge of the screen. The below solution can be used anywhere regardless of layout position. This is for right side drawable touch.
textView.setOnTouchListener(OnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_UP)
{
if (event.x >= textView.width - textView.totalPaddingEnd)
{
<!---DO YOUR ACTIONS HERE--->
return#OnTouchListener true
}
}
true
})
PS: Kotlin code

Categories

Resources