Adding span to text causes scrolling to cursor position inside EditText - android

To be more specific I've done small example of this behaviour.
Layout:
<ScrollView
android:id="#+id/scroll_view_for_et"
android:scrollbars="horizontal"
android:layout_height="fill_parent"
android:layout_width="fill_parent">
<EditText
android:id="#+id/edit_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="top"
android:text="Long text there" />
</ScrollView>
Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText editText = (EditText) findViewById(R.id.edit_text);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//Adding random span to text
editText.getEditableText().setSpan(new ForegroundColorSpan(Color.RED), 100, 500, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}, 7000);
}
So if I set a cursor in some place, and then scrolling text in other position, after 7 seconds passed it will be scrolled back to coursor position. How to avoid this behaviour?
BitBucket link for full code of this example.

I found some solution. Issue was in that EditText recieved a focus after execution of setSpan method. So I've added android:descendantFocusability="beforeDescendants" to parent element in my view hierarchy ( in my case it was LinearLayout), and OnTouchListener to ScrollView:
mScrollViewAroundEt.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (mCustomEditText.hasFocus()) {
mCustomEditText.clearFocus();
}
return false;
}
});
So now EditText do not recieve focus when user scroll.

Related

Best way to unfocus edittext when user interacts with another (non-texual) input element

I have an activity with some edittexts and some checkboxes, etc.
I have validators set on text entries that get executed when a text entry loses focus. But the problem is when the user clicks/touches a checkbox, edittext doesn't lose focus and therefore the validator is not run.
What is the best way for causing unfocus of text entries when the user touches another input field? I know I can e.g. set a handler on every checkbox to force unfocusing of text fields happen, but I think there is probably a more concise/general method for this purpose; Setting a handler on every checkbox seems too cumbersome and error prone.
thank u.
You can try this way(it only is an example).
your_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/sv_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusableInTouchMode="true"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="EditText 1" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="EditText 2" />
..............other views................
</LinearLayout>
</ScrollView>
Using android:focusableInTouchMode="true" in the LinearLayout to make the EditText is focused when touching on it( or when starting this activity there is not auto focus to any EditText also).
In your activity:
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
ScrollView svContent = findViewById(R.id.sv_content);
svContent.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
int action = motionEvent.getAction();
if(action == MotionEvent.ACTION_MOVE || action == MotionEvent.ACTION_UP) {
View focusView = getCurrentFocus();
if (focusView != null) {
// The code for unfocus here
return true;
}
}
return false;
}
});
}

scrolling jerky before braking when single edittext inside scrollview

I'm writing a simple text editor in my app. Accordingly, I need to scroll through a large editable text.
My layout:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scroll"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText
android:id="#+id/note"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/black"
android:padding="5dp"
android:textSize="14sp"/>
</ScrollView>
In my Activity I set large text :
public class FileEditorActivity extends Activity {
private EditText text;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file_editor);
text = (EditText)findViewById(R.id.note);
text.setText(newText); ////// LARGE TEXT
}
}
Now, text scrolls but when the scroll speed is reduced scrolling starts to twitch (jerky)!!!!!!
I thought why so ......... And try the following :
scrollView = (ScrollView)findViewById(R.id.scroll);
scrollView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
scrollView.setFocusable(true);
scrollView.setFocusableInTouchMode(true);
scrollView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
v.requestFocusFromTouch();
if (text.hasFocus()) {
text.clearFocus();
}
return false;
}
});
And after that (when edittext always lost focus before scrolling) scroll large text working perfect when the scroll speed is reduced.
But I need to always stay in focus and maintain the state of the cursor when scrolling text ((((
How to do it ?????????
P.S. I want to like this :
ES Explorer app
When open text file on edit
Thanks in advance !!!!

How to Move cursor from one EditText to another one and back to the first edit text if a custom button is clicked?

i am basically developing a small mathematics app, in a activity their will be problems like additions subtractions etc. the user has to fill the answers in edittext from the custom buttons from 0-9, a dot, a slash button and a backspace button which i created on the same activity. now i like to add up and down button, so that when the up button is pressed the cursor has to move towards upside edit text and vice versa.
here is a sample code which i used
XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="#android:id/et1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Some string of text"
/>
<EditText
android:id="#android:id/et2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Some string of text"
/>
<Button
android:id="#android:id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button"
/>
</LinearLayout>
Class:
public class Example extends Activity {
TextView et1;
TextView et2;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
et1 = (EditText) findViewById(android.R.id.et1);
et2 = (EditText) findViewById(android.R.id.et2);
Button button = (Button) findViewById(android.R.id.button1);
button.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
Selection.setSelection((Editable) et2.getText(), et1.getSelectionStart());
et2.requestFocus();
}
});
}
}
You could create an array of of your EditTexts and a variable containing your current position, defaulted to 0, meaning the first text box. Then if the user presses the up button, if the variable is greater than 0, set the position -1 and then get the textbox object from the array and call focus(). Below is an example piece of code, its not accurate but should get you started
List<EditText> textfields = null;
int currentTextFieldPosition = 0;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
textfields = new ArrayList<EditText>();
textfield1 = (EditText)findViewById(R.id.textfield1);
.....
textfields.add(textfield1);
......
}
protected OnClickListener mBtnUpClickListener = new OnClickListener()
{
public boolean onClick()
{
if (currentTextfieldPosition > 0)
{
currentTextfieldPosition--;
textfields.get(currentTextFieldPosition).focus()
}
}
}

Keyboard not shown on inflated editText even after clicking on it

Background
I have a form-like activity, which has some views that can be created dynamically upon pressing.
I'm using an xml for each field that is inflated upon clicking on a button.
What I need is that upon choosing to add a new item, it will get focus, scroll if needed, and show the keyboard so that the user can type things into it. The keyboard may be shown upon adding the field or when clicking on the EditText.
The problem
For some reason, on some devices (and I don't think it's even an android version issue) when inflating the new view, the editText within it can get focus but it doesn't show the keyboard, even if it has focus and the user clicks on it.
In such a case, the only way to show the keyboard is to click on another EditText.
I've tested it, and noticed that it doesn't occur when I don't use xml at all, meaning when i create the views only in code.
The question
Why does it occur? What can I do in order to fix it?
I've already tried so many possible solutions, but none work on all devices.
Sample Code
the next code has the described issue on xperia j (android 4.0.4) an galaxy mini (android 2.3.6) .
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ViewGroup container = (ViewGroup) findViewById(R.id.LinearLayout1);
final LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
findViewById(R.id.button).setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View v) {
final View view = inflater.inflate(R.layout.field, null);
// using the next code works when using it instead of inflating a layout:
// final EditText editText = new EditText(MainActivity.this);
// editText.setText("item " + container.getChildCount());
container.addView(view);
}
});
}
the field layout file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/RelativeLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFffffff"
android:gravity="center_vertical" >
<Spinner
android:id="#+id/typeSpinner"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_centerVertical="true"
android:background="#null"
android:padding="5dp" />
<include
android:id="#+id/removeItemView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
layout="#layout/remove_item_view" />
<EditText
android:id="#+id/fieldEditText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="#+id/removeItemView"
android:layout_toRightOf="#+id/typeSpinner"
android:ems="10"
android:focusable="true"
android:focusableInTouchMode="true"
android:hint="field"
android:imeOptions="actionDone"
android:inputType="phone"
android:minWidth="200dp"
android:padding="5dp"
android:singleLine="true"
tools:ignore="HardcodedText" >
<requestFocus />
</EditText>
</RelativeLayout>
the main layout file:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="#+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="click"
tools:ignore="HardcodedText" />
</LinearLayout>
</ScrollView>
EDIT: found a partial solution which won't show the keyboard right away, but at least it will be shown when pressing the editText:
public static void forceFocusOnView(final View view) {
if (view == null)
return;
view.post(new Runnable() {
#Override
public void run() {
view.clearFocus();
view.post(new Runnable() {
#Override
public void run() {
view.requestFocus();
}
});
}
});
}
I'm not sure in a reason of that problem. Could be some missmatches when Android sdk were rewritten in order to match some devices.
So I think that the best solution to you is to show your keyboard manually and do not try to move a train, just take the path of the least resistance:
EditText et=(EditText)this.findViewById(R.id.edit_text);
et.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(et, 0);<----------------
}
});
Here you go , man. Wish you luck.
Oh i see...
private EditText et;
private Runnable setFocus;
......
protected void onCreate(...){
.
.
.
setFocus=new Runnable(){
#Override
public void run() {
et.requestFocus();
}
};
}
....
findViewById(R.id.button).setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View v) {
final View view = inflater.inflate(R.layout.field, null);
//try this:
et=(EditText)view.findViewById(r.id.fieldEditText);
et.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(et, 0);<----------------
}
});
container.addView(view);
container.requestLayout();<--------------
et.postDelayed(setFocus,300);
}
});

Editview press softkey Return, lose focus AND hide keyboard, how?

I'm working on an Android app and I've got 2 editviews and a label. The user can enter 2 values and the label shows some calculation using input from the editviews. What I want is the following;
user enters either value with soft-keyboard
user presses "Return" softkey
editview should lose focus
the soft-keyboard should disappear
textview label should be recalculated
Now, the v.clearFocus only seems to works when there is another widget that can can get focus(?), so I've also added a dummie zero-pixel layout that can 'steal' the focus from the first editview. The Return key works now, but when the user switches focus from edit1 to edit2 by simply tapping then HideKeyboard() crashes. I've tried checking if inputMethodManager==null but that didn't help.
This all feels like I'm hacking to trick Android into doing some common UI behaviour, so I can't help but think that I'm overlooking something here.
Any help would be greatly appreciated. Btw I know this is similar to this question: How to lose the focus of a edittext when "done" button in the soft keyboard is pressed?
But I've tried that and it doesn't work.
So my layout xml is this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- Dummy control item so that first textview can lose focus -->
<LinearLayout
android:focusable="true"
android:focusableInTouchMode="true"
android:layout_width="0px"
android:layout_height="0px"/>
<EditText
android:id="#+id/editTest1"
android:layout_width="250px"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:imeOptions="actionDone" >
</EditText>
<EditText
android:id="#+id/editTest2"
android:layout_width="250px"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:imeOptions="actionDone" >
</EditText>
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test123" />
</LinearLayout>
And the source is this:
public class CalcActivity extends Activity implements OnFocusChangeListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tab2_weight);
EditText testedit = (EditText) findViewById(R.id.editTest1);
testedit.setOnFocusChangeListener(this);
testedit.setOnEditorActionListener(new OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if(actionId==EditorInfo.IME_ACTION_DONE){
//Clear focus here from edittext
Log.d("test app", "v.clearFocus only works when there are other controls that can get focus(?)");
v.clearFocus();
}
return false;
}
});
}
public void hideSoftKeyboard() {
InputMethodManager inputMethodManager = (InputMethodManager) this.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0);
}
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus == false) {
Log.d("unitconverter", "onFocusChange hasFocus == false");
// update textview label
TextView bla = (TextView) findViewById(R.id.textView1);
bla.setText(String.format("%s + %s", (((EditText) findViewById(R.id.editTest1)).getText()), (((EditText) findViewById(R.id.editTest2)).getText())));
// hide keyboard
hideSoftKeyboard();
}
}
}

Categories

Resources