I am working on app where i use Urdu Custom Keyboard its work fine but the problem is that when i type any-word e.g. (سلام), cursor become not works at mid character for example cut/copy/paste or deleting (ا) character from the mid from word are not work.
i uses rough technique just appending characters but is also work fine.
For taping any alphabetic
private void addText(View v) {
// String b = "";
// b = (String) v.getTag();
// urdu_word.setText(b);
if (isEdit == true) {
String b = "";
b = (String) v.getTag();
if (b != null) {
Log.i("buttonsOnclick", b);
// adding text in Edittext
mEt.append(b);
}
}
}
For back button tapping
private void isBack(View v) {
if (isEdit == true) {
CharSequence cc = mEt.getText();
if (cc != null && cc.length() > 0) {
{
mEt.setText("");
mEt.append(cc.subSequence(0, cc.length() - 1));
}
}
}
}
Here the screenshot clear my problem to you people
I used a lot of library and code from github but don't catch good idea
1) Keyboard-1
2) Keyboard-2
3) Keyboard-3
4) Keyboard-4
i checked all these keyboard and more from libs, have same cursor issue, how to manage fully my custom keyboard by deleting character from mid and copy my written text copy paste like normal keyboard with EditText, thanks in advance all of you :)
Thanks God i solved my issue using simple logic.
For back button
private void isBack(View v) {
// char[] tempChar = null;
if ((mEt.getText().toString().length() > 0)) {
int temp = mEt.getSelectionEnd() - 1;
if (temp >= 0) {
mEt.setText((mEt.getText().toString()
.substring(0, mEt.getSelectionEnd() - 1).concat(mEt
.getText()
.toString()
.substring(mEt.getSelectionEnd(),
mEt.getText().length()))));
mEt.setSelection(temp);
}
}
}
For adding any character
private void addText(View v) {
int temp = mEt.getSelectionEnd();
if (temp >= 0) {
String b = "";
b = (String) v.getTag();
mEt.setText((mEt.getText().toString()
.substring(0, mEt.getSelectionEnd()) + b.concat(mEt
.getText().toString()
.substring(mEt.getSelectionEnd(), mEt.getText().length()))));
mEt.setSelection(temp + 1);
}
}
for copy paste i added few lines code to EditText
<EditText
android:id="#+id/xEt"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="#drawable/edittextshape"
android:ems="10"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="top"
android:imeOptions="actionDone"
android:padding="15dp"
android:singleLine="false"
android:visibility="visible" />
Related
I try set my html text on TextView like this
my_text.setText(HtmlCompat.fromHtml("<p>This is the awesome place to gain</p><p><strong>awesomeness </strong>and <em>deliciuosness. </em>very<em> </em><u>nice</u></p>", HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH))
I try set the TextView with a border, And I got padding bottom like this.
How to remove that? Because My TextView doesn't set anything
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="#+id/my_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/border_black_fill_white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
In kotlin it's just using trim() method:
val stringHtml = "<p>This is the awesome place to gain</p><p><strong>awesomeness </strong>and <em>deliciuosness. </em>very<em> </em><u>nice</u></p>"
val spannedHtml = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(stringHtml, Html.FROM_HTML_MODE_COMPACT)
} else {
Html.fromHtml(stringHtml)
}
my_text.text = spannedHtml.trim()
This extra space that you see is infact line break followed by another line break.
When you dive into the Html.fromHtml(...) implementation which is used internally by HtmlCompat.fromHtml, you'll come across the following method that handles paragraph tags:
private static void handleP(SpannableStringBuilder text) {
int len = text.length();
if (len >= 1 && text.charAt(len - 1) == '\n') {
if (len >= 2 && text.charAt(len - 2) == '\n') {
return;
}
text.append("\n");
return;
}
if (len != 0) {
text.append("\n\n");
}
}
So to handle this just trim the string so space added at the end gets removed.
String html = "<p>This is the awesome place to gain</p><p><strong>awesomeness </strong>and <em>deliciuosness. </em>very<em> </em><u>nice</u></p>"
CharSequence trimmedString = trim(Html.fromHtml(html));
myText.setText(trimmedString);
public static CharSequence trim(CharSequence s) {
int start = 0;
int end = s.length();
while (start < end && Character.isWhitespace(s.charAt(start))) {
start++;
}
while (end > start && Character.isWhitespace(s.charAt(end - 1))) {
end--;
}
return s.subSequence(start, end);
}
This will give you the desired result.
As far as I can see, all existing answers turn the Spanned into a regular string, which removes the additional information in the Spanned. This Kotlin code is preserving the Spanned structure (including links):
fun Spanned.trim() {
if (this is SpannableStringBuilder) {
while (length > 0 && this[length-1].isWhitespace()) {
delete(length-1, length)
}
while (length > 0 && this[0].isWhitespace()) {
delete(0, 1)
}
}
}
Use it like this:
val html = HtmlCompat.fromHtml(rawContent, HtmlCompat.FROM_HTML_MODE_LEGACY)
html.trim()
Check once if you have given any bottom padding to TextView in the html file which is set as a background .
Try below code as well..
String strHtml = "<br>This is the awesome place to gain</br><br><strong>awesomeness </strong>and <em>deliciuosness. </em>very<em> </em><u>nice</u></br>";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
my_text.setText(Html.fromHtml(strHtml, Html.FROM_HTML_MODE_COMPACT));
} else {
my_text.setText(Html.fromHtml(strHtml));
}
I had a problem when I type the text I do not want the keyboard changes automatically, but after a space keyboard changes to the original state.
For example, I want to dial numbers that I move into this state the keyboard: But when I need to enter the number followed by a space, the keyboard itself is changed automatically:And it is necessary that the user himself can change the state of the keyboard, if it is necessary to enter characters. I use a mask on the text of Edit Text. With the help of this library set mask: MaskFormatter. an example of a mask: private static final String MASK = "99 AA 999999";
private EditText mInputCertificate;
#Override
public void setViews(View rootView, Bundle savedInstanceState) {
// Some code
mInputCertificate = (EditText) rootView.findViewById(R.id.input_car_certificate);
MaskFormatter maskFormatter = new MaskFormatter(MASK, mInputCertificate);
mInputCertificate.addTextChangedListener(maskFormatter);
}
There are ways to solve this problem?
I made my custom TextWatcher for EditText:
private String getString (String s) {
String newValue = s.replaceAll("\\s", "");
/*if (newValue.length() < 2 || newValue.length() >= 4) {
mEditText.setInputType(InputType.TYPE_CLASS_NUMBER);
} else {
mEditText.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
}*/
StringBuilder builder = new StringBuilder();
for (int i =0; i < newValue.length(); i++) {
if (i == 2 || i == 4) {
builder.append(' ');
builder.append(newValue.charAt(i));
} else {
builder.append(newValue.charAt(i));
}
}
return builder.toString();
}
#Override
public void afterTextChanged(Editable s) {
Log.d("EDITTEXT", "getEditable " + s);
String text = getString(s.toString());
mEditText.removeTextChangedListener(this);
mEditText.getText().clear();
mEditText.append(text.toUpperCase());
mEditText.addTextChangedListener(this);
mEditText.setSelection(mEditText.length());
}
This work for me. And I used .append(SomeText) instead .setText(SomeText).
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
http://www.itechcode.com/2012/03/18/create-calculator-in-android-programming/
Im using his source code but it seems very different than the "Beginner Level" Programming I have been use to i.e. creating new project, modifying layout, referencing in main.java, etc.
I'm trying to use his source code and modify/create new operations and maybe add a activity. I would usually know how to do most of that stuff if it wasn't laid out differently. Thank You!
package com.pragmatouch.calculator;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Iterator;
import java.util.Stack;
import android.app.Activity;
import android.os.Bundle;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.view.View;
import android.view.View.OnClickListener;
public class main extends Activity {
GridView mKeypadGrid;
TextView userInputText;
TextView memoryStatText;
Stack<String> mInputStack;
Stack<String> mOperationStack;
KeypadAdapter mKeypadAdapter;
TextView mStackText;
boolean resetInput = false;
boolean hasFinalResult = false;
String mDecimalSeperator;
double memoryValue = Double.NaN;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DecimalFormat currencyFormatter = (DecimalFormat) NumberFormat
.getInstance();
char decimalSeperator = currencyFormatter.getDecimalFormatSymbols()
.getDecimalSeparator();
mDecimalSeperator = Character.toString(decimalSeperator);
setContentView(R.layout.main);
// Create the stack
mInputStack = new Stack<String>();
mOperationStack = new Stack<String>();
// Get reference to the keypad button GridView
mKeypadGrid = (GridView) findViewById(R.id.grdButtons);
// Get reference to the user input TextView
userInputText = (TextView) findViewById(R.id.txtInput);
userInputText.setText("0");
memoryStatText = (TextView) findViewById(R.id.txtMemory);
memoryStatText.setText("");
mStackText = (TextView) findViewById(R.id.txtStack);
// Create Keypad Adapter
mKeypadAdapter = new KeypadAdapter(this);
// Set adapter of the keypad grid
mKeypadGrid.setAdapter(mKeypadAdapter);
// Set button click listener of the keypad adapter
mKeypadAdapter.setOnButtonClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Button btn = (Button) v;
// Get the KeypadButton value which is used to identify the
// keypad button from the Button's tag
KeypadButton keypadButton = (KeypadButton) btn.getTag();
// Process keypad button
ProcessKeypadInput(keypadButton);
}
});
mKeypadGrid.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
}
});
}
private void ProcessKeypadInput(KeypadButton keypadButton) {
//Toast.makeText(this, keypadButton.getText(), Toast.LENGTH_SHORT).show();
String text = keypadButton.getText().toString();
String currentInput = userInputText.getText().toString();
int currentInputLen = currentInput.length();
String evalResult = null;
double userInputValue = Double.NaN;
switch (keypadButton) {
case BACKSPACE: // Handle backspace
// If has operand skip backspace
if (resetInput)
return;
int endIndex = currentInputLen - 1;
// There is one character at input so reset input to 0
if (endIndex < 1) {
userInputText.setText("0");
}
// Trim last character of the input text
else {
userInputText.setText(currentInput.subSequence(0, endIndex));
}
break;
case SIGN: // Handle -/+ sign
// input has text and is different than initial value 0
if (currentInputLen > 0 && currentInput != "0") {
// Already has (-) sign. Remove that sign
if (currentInput.charAt(0) == '-') {
userInputText.setText(currentInput.subSequence(1,
currentInputLen));
}
// Prepend (-) sign
else {
userInputText.setText("-" + currentInput.toString());
}
}
break;
case CE: // Handle clear input
userInputText.setText("0");
break;
case C: // Handle clear input and stack
userInputText.setText("0");
clearStacks();
break;
case DECIMAL_SEP: // Handle decimal seperator
if (hasFinalResult || resetInput) {
userInputText.setText("0" + mDecimalSeperator);
hasFinalResult = false;
resetInput = false;
} else if (currentInput.contains("."))
return;
else
userInputText.append(mDecimalSeperator);
break;
case DIV:
case PLUS:
case MINUS:
case MULTIPLY:
if (resetInput) {
mInputStack.pop();
mOperationStack.pop();
} else {
if (currentInput.charAt(0) == '-') {
mInputStack.add("(" + currentInput + ")");
} else {
mInputStack.add(currentInput);
}
mOperationStack.add(currentInput);
}
mInputStack.add(text);
mOperationStack.add(text);
dumpInputStack();
evalResult = evaluateResult(false);
if (evalResult != null)
userInputText.setText(evalResult);
resetInput = true;
break;
case CALCULATE:
if (mOperationStack.size() == 0)
break;
mOperationStack.add(currentInput);
evalResult = evaluateResult(true);
if (evalResult != null) {
clearStacks();
userInputText.setText(evalResult);
resetInput = false;
hasFinalResult = true;
}
break;
case M_ADD: // Add user input value to memory buffer
userInputValue = tryParseUserInput();
if (Double.isNaN(userInputValue))
return;
if (Double.isNaN(memoryValue))
memoryValue = 0;
memoryValue += userInputValue;
displayMemoryStat();
hasFinalResult = true;
break;
case M_REMOVE: // Subtract user input value to memory buffer
userInputValue = tryParseUserInput();
if (Double.isNaN(userInputValue))
return;
if (Double.isNaN(memoryValue))
memoryValue = 0;
memoryValue -= userInputValue;
displayMemoryStat();
hasFinalResult = true;
break;
case MC: // Reset memory buffer to 0
memoryValue = Double.NaN;
displayMemoryStat();
break;
case MR: // Read memoryBuffer value
if (Double.isNaN(memoryValue))
return;
userInputText.setText(doubleToString(memoryValue));
displayMemoryStat();
break;
case MS: // Set memoryBuffer value to user input
userInputValue = tryParseUserInput();
if (Double.isNaN(userInputValue))
return;
memoryValue = userInputValue;
displayMemoryStat();
hasFinalResult = true;
break;
case PRGM:
break;
default:
if (Character.isDigit(text.charAt(0))) {
if (currentInput.equals("0") || resetInput || hasFinalResult) {
userInputText.setText(text);
resetInput = false;
hasFinalResult = false;
} else {
userInputText.append(text);
resetInput = false;
}
}
break;
}
}
private void clearStacks() {
mInputStack.clear();
mOperationStack.clear();
mStackText.setText("");
}
private void dumpInputStack() {
Iterator<String> it = mInputStack.iterator();
StringBuilder sb = new StringBuilder();
while (it.hasNext()) {
CharSequence iValue = it.next();
sb.append(iValue);
}
mStackText.setText(sb.toString());
}
private String evaluateResult(boolean requestedByUser) {
if ((!requestedByUser && mOperationStack.size() != 4)
|| (requestedByUser && mOperationStack.size() != 3))
return null;
String left = mOperationStack.get(0);
String operator = mOperationStack.get(1);
String right = mOperationStack.get(2);
String tmp = null;
if (!requestedByUser)
tmp = mOperationStack.get(3);
double leftVal = Double.parseDouble(left.toString());
double rightVal = Double.parseDouble(right.toString());
double result = Double.NaN;
if (operator.equals(KeypadButton.DIV.getText())) {
result = leftVal / rightVal;
} else if (operator.equals(KeypadButton.MULTIPLY.getText())) {
result = leftVal * rightVal;
} else if (operator.equals(KeypadButton.PLUS.getText())) {
result = leftVal + rightVal;
} else if (operator.equals(KeypadButton.MINUS.getText())) {
result = leftVal - rightVal;
}
String resultStr = doubleToString(result);
if (resultStr == null)
return null;
mOperationStack.clear();
if (!requestedByUser) {
mOperationStack.add(resultStr);
mOperationStack.add(tmp);
}
return resultStr;
}
private String doubleToString(double value) {
if (Double.isNaN(value))
return null;
long longVal = (long) value;
if (longVal == value)
return Long.toString(longVal);
else
return Double.toString(value);
}
private double tryParseUserInput() {
String inputStr = userInputText.getText().toString();
double result = Double.NaN;
try {
result = Double.parseDouble(inputStr);
} catch (NumberFormatException nfe) {
}
return result;
}
private void displayMemoryStat() {
if (Double.isNaN(memoryValue)) {
memoryStatText.setText("");
} else {
memoryStatText.setText("M = " + doubleToString(memoryValue));
}
}
}
ENUM:
package com.pragmatouch.calculator;
public enum KeypadButton {
MC("MC",KeypadButtonCategory.MEMORYBUFFER)
, MR("MR",KeypadButtonCategory.MEMORYBUFFER)
, MS("MS",KeypadButtonCategory.MEMORYBUFFER)
, M_ADD("M+",KeypadButtonCategory.MEMORYBUFFER)
, M_REMOVE("M-",KeypadButtonCategory.MEMORYBUFFER)
, BACKSPACE("<-",KeypadButtonCategory.CLEAR)
, CE("CE",KeypadButtonCategory.CLEAR)
, C("C",KeypadButtonCategory.CLEAR)
, ZERO("0",KeypadButtonCategory.NUMBER)
, ONE("1",KeypadButtonCategory.NUMBER)
, TWO("2",KeypadButtonCategory.NUMBER)
, THREE("3",KeypadButtonCategory.NUMBER)
, FOUR("4",KeypadButtonCategory.NUMBER)
, FIVE("5",KeypadButtonCategory.NUMBER)
, SIX("6",KeypadButtonCategory.NUMBER)
, SEVEN("7",KeypadButtonCategory.NUMBER)
, EIGHT("8",KeypadButtonCategory.NUMBER)
, NINE("9",KeypadButtonCategory.NUMBER)
, PLUS(" + ",KeypadButtonCategory.OPERATOR)
, MINUS(" - ",KeypadButtonCategory.OPERATOR)
, MULTIPLY(" * ",KeypadButtonCategory.OPERATOR)
, DIV(" / ",KeypadButtonCategory.OPERATOR)
, RECIPROC("1/x",KeypadButtonCategory.OTHER)
, DECIMAL_SEP(",",KeypadButtonCategory.OTHER)
, SIGN("±",KeypadButtonCategory.OTHER)
, SQRT("SQRT",KeypadButtonCategory.OTHER)
, PERCENT("%",KeypadButtonCategory.OTHER)
, CALCULATE("=",KeypadButtonCategory.RESULT)
, PRGM("PRGM",KeypadButtonCategory.PRGM)
, DUMMY("",KeypadButtonCategory.DUMMY);
CharSequence mText; // Display Text
KeypadButtonCategory mCategory;
KeypadButton(CharSequence text,KeypadButtonCategory category) {
mText = text;
mCategory = category;
}
public CharSequence getText() {
return mText;
}
}
package com.pragmatouch.calculator;
public enum KeypadButtonCategory {
MEMORYBUFFER
, NUMBER
, OPERATOR
, DUMMY
, CLEAR
, RESULT
, OTHER
, PRGM
}
I have a great answer for you. I recently wanted to create my own button in android but I wanted to do it in a simple way. Follow these steps and in a few minutes I will post pictures.
1) create a new layout. start with a LinearLayout. Nest a FramedLayout and another LinearLayout inside of it.
2) then add a TextView to it. This is where practice makes perfect. Play around with the attributes. Learn what they do. when you have the general information of how you want your button to be display go to the next step.
3) what your are going to do is include this in another view as a button. You can use a specific attribute to make it look like a button as well.
Give me a few minutes and I will post some code and a picture.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/CBN_LinearLayout"
style="#android:style/Widget.Button"
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/CBV_texview1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginRight="10dp"
android:layout_weight="1"
android:gravity="right"
android:text="#string/checkorder"
android:textColor="#color/Black" />
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1" >
<ImageView
android:id="#+id/CBV_imageView1"
android:layout_width="23dp"
android:layout_height="15dp"
android:layout_gravity="center_vertical"
android:contentDescription="#string/redcirclenotify"
android:src="#drawable/rednotify"
android:visibility="visible" />
<TextView
android:id="#+id/CBV_textview2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dp"
android:gravity="left"
android:text="#string/zero"
android:visibility="visible" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/CBV_textview3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:fadingEdge="horizontal"
android:gravity="center_horizontal"
android:text="#string/blankstring" />
<TextView
android:id="#+id/CBV_textview4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:text="#string/blankstring" />
</LinearLayout>
when you add it to another view as a button you use:
<include
android:id="#+id/MI_checkorder"
style="android:buttonStyle"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_gravity="bottom"
android:layout_marginTop="5dp"
android:layout_weight="1"
layout="#layout/custombtnview"
android:background="#style/AppTheme"
android:clickable="true"
android:focusable="true" />
The important part of this is setting the Style for the root LinearLayout to #android:style/Widget.Button
Once this is done it will look like a button and work like a button.
Below is an image of the final product:
another part of your question. Adjust sizes of standard buttons in android:
1) almost everything can be controled with how you use the XML. This can all be controled in the area to right, in the ADK. These attributes help you to control almost every aspect.
for example as in the calculator...
you have 4 buttons in a row so you want to add 4 buttons inside of a horizontal LinearLayout. Then you can give the a weight of 1 for each button then set their Width to FillParent. This will auto size the buttons to be displayed in the width of the screen equally.
Am I better off making my own calc or modify the existing code?
I would never tell someone to recreate the wheel, however, if you do not understand the code well enough to pickup where they left off then this can be an uphill struggle for you. Your best bet if you are having trouble understanding the code given to you or how to modify it, would be to actually post the code in another question and be very specific and ask for example how can I change what this particular button displays and what the result of clicking it would be. This forum depends on the people asking the questions to be clear and concise. If not then questions will closed as fast as they are opened. Generalizations are severely frowned upon on the site.
In the end, what I am trying to do is make my own scientific calculator but I don't want to spend extra time doing the simple operations.
The best way to answer this is to take a look at how the calculator is assembled in the GUI or Graphical Layout. Try changing a button and what it does. for example make the plus a minus just for the learning curve.
1) look for , PLUS(" + ",KeypadButtonCategory.OPERATOR) and notice that is a string for plus. change it to " T " see if it changes in the app. If it does then go into the code. In the code you will find case CALCULATE: for for the = sign in the ENUM and then inside that you find evalResult = evaluateResult(true);. If you follow this you reach:
if (operator.equals(KeypadButton.DIV.getText())) {
result = leftVal / rightVal;
} else if (operator.equals(KeypadButton.MULTIPLY.getText())) {
result = leftVal * rightVal;
} else if (operator.equals(KeypadButton.PLUS.getText())) {
result = leftVal + rightVal;
} else if (operator.equals(KeypadButton.MINUS.getText())) {
result = leftVal - rightVal;
}
so now you can change result = leftVal + rightVal; to result = leftVal - rightVal; and you have just changed it. so it will take some time to understand the code but you have to do some trial and error to understand it. I hope this helps answer your question.
In my layout xml, I use the following to define an EditText that can display currency.
<EditText
android:id="#+id/et1"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:imeOptions= "actionNext"
android:inputType="phone"
android:digits="0123456789.,$" >
However, this is not localized. I want to be able to use the symbol returned by NumberFormat.getCurrencyInstance().getCurrency().getSymbol(); in place of the $ in android:digits.
What I don't know is how to set android:digits from within my program.
Solved thanks to Agarwal. I just need to read the documentation more thoroughly.
Try this:
<EditText
android:inputType="number"
android:digits="0123456789."
/>
From Code:
weightInput.setKeyListener(DigitsKeyListener.getInstance("0123456789."));
But, it allows the user to include several "."
You can also do this for accepting on digits...
EditText input = new EditText(this);
input.setInputType(InputType.TYPE_CLASS_NUMBER);
Yes you can check here
http://developer.android.com/reference/android/widget/EditText.html
for almost every attribute there is equivalent method present.
setKeyListener(KeyListener)
For those interested, here is how I solved the original question. It is the complete implementation of a currency edit text that can handle multiple locales. Still may be some problems (Doesn't seem to display Japanese currency symbol correctly, and I can't get the keyboard I want (12_KEY)), but otherwise, some may find this helpful.
public class CurrencytestActivity extends Activity
{
private static final Integer MAX_VALUE_DIGITS = 9;
EditText et1;
NumberFormat mCurrencyFormatter;
CurrencyTextWatcher tw;
#Override public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Get info about local currency
mCurrencyFormatter = NumberFormat.getCurrencyInstance();
int fractionDigits = mCurrencyFormatter.getCurrency().getDefaultFractionDigits();
et1 = (EditText)findViewById(R.id.et1); // Get a handle to the TextEdit control
// Add local currency symbol to digits allowed for EditText display and use
// DigitsKeyListener to tell the control. Unfortunately, this also resets the inputType
// that is specified in the XML layout file. Don't know how to fix that yet.
// Also, this doesn't seem to work for Japanese (probably due to UNICODE or something).
// The symbol gets added to displayCharacters, but the EditText doesn't use it.
String displayCharacters = "0123456789.," + mCurrencyFormatter.getCurrency().getSymbol();
et1.setKeyListener(DigitsKeyListener.getInstance( displayCharacters ));
// Add a text watcher to the EditText to manage currency digit entry. The TextWatcher
// won't allow the symbol or decimal or comma to be entered by the user, but they are
// still displayed when the result is formatted in afterTextChanged().
tw = new CurrencyTextWatcher( MAX_VALUE_DIGITS, fractionDigits );
et1.addTextChangedListener( tw );
et1.setCursorVisible( false );
((Button)findViewById(R.id.button1)).setOnClickListener(onButtonClick);
}
public class CurrencyTextWatcher implements TextWatcher
{
boolean mEditing; // Used to prevent recursion
Double mAmount;
int mDigitCount, mMaxDigits, mFractionDivisor;
public CurrencyTextWatcher( int maxDigits, int fractionDigits )
{
mEditing = false;
mFractionDivisor = (fractionDigits == 0) ? 1 : ((fractionDigits == 1) ? 10 : 100);
mAmount = 0.0;
mDigitCount = 0;
mMaxDigits = maxDigits;
}
public synchronized void afterTextChanged(Editable s)
{
// Don't update EditText display if we are editing
if ( !mEditing )
{
// Under cover of mEditing, update the EditText display with
// the newly formatted value
mEditing = true;
s.replace( 0, s.length(), mCurrencyFormatter.format( mAmount ));
mEditing = false;
}
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
public double GetAmount() { return( mAmount ); }
public void onTextChanged(CharSequence s, int start, int before, int count)
{
if ( !mEditing )
{
// Added a digit to the value
if (( count == 1 ) && ( mDigitCount < mMaxDigits ))
{
// Obtain the added character
CharSequence x = s.subSequence( start, start + count );
// Ignore any characters other than number digits for addition to value
if (( x.charAt( 0 ) >= '0') && ( x.charAt( 0 ) <= '9'))
{
// Multiply by ten to shift existing digits to the left and
// add in the new digit as the decimal place appropriate to this currency
mAmount = (mAmount * 10) + (Double.parseDouble( x.toString() ) / mFractionDivisor);
mDigitCount += 1;
}
}
// Delete last digit from the value
else if (( count == 0 ) && ( mDigitCount > 0))
{
// Subtract the amount of the last digit and divide by ten to
// effectively delete the last character entered
mAmount -= (mAmount % (0.001 * mFractionDivisor) );
mAmount /= 10;
mDigitCount -= 1;
}
}
}
}
private View.OnClickListener onButtonClick = new View.OnClickListener()
{
#Override public void onClick(View v)
{
if (v.getId() == R.id.button1 )
{
// Get the value from the textwatcher and display it.
double mAmountTest = tw.GetAmount();
((TextView)findViewById(R.id.tv1)).setText(mCurrencyFormatter.format( mAmountTest ));
}
}
};
}
And the accompanying XML layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center|top"
android:orientation="vertical" >
<EditText
android:id="#+id/et1"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:imeOptions= "actionNext"
android:inputType="phone" >
<requestFocus />
</EditText>
<TextView
android:id="#+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Extract from TextWatcher" />
</LinearLayout>
I'm developping an app which constantly needs to show the results to the user in a TextView like some sort of log.
The app works nicely and it shows the results in the TextView but as long as it keeps running and adding lines the app gets slower and crashes because of the character length of the TextView.
I would like to know if the android API provides any way to force a TexView to automatically delete the oldest lines that were introduced in order to make room for the new ones.
I had the same problem. I just resolved it.
The trick is to use the getEditableText() method of TextView. It has a replace() method, even a delete() one. As you append lines in it, the TextView is already marked as "editable", which is needed to use getEditableText(). I have something like that:
private final static int MAX_LINE = 50;
private TextView _debugTextView; // Of course, must be filled with your TextView
public void writeTerminal(String data) {
_debugTextView.append(data);
// Erase excessive lines
int excessLineNumber = _debugTextView.getLineCount() - MAX_LINE;
if (excessLineNumber > 0) {
int eolIndex = -1;
CharSequence charSequence = _debugTextView.getText();
for(int i=0; i<excessLineNumber; i++) {
do {
eolIndex++;
} while(eolIndex < charSequence.length() && charSequence.charAt(eolIndex) != '\n');
}
if (eolIndex < charSequence.length()) {
_debugTextView.getEditableText().delete(0, eolIndex+1);
}
else {
_debugTextView.setText("");
}
}
}
The thing is, TextView.getLineCount() returns the number of wrapped lines, and not the number of "\n" in the text... It is why I clear the whole text if I reach the end of the text while seeking the lines to delete.
You can do that differently by erasing a number of characters instead of erasing a number of lines.
This solution keeps track of the log lines in a list and overwrites the textview with the contents of the list on each change.
private List<String> errorLog = new ArrayList<String>();
private static final int MAX_ERROR_LINES = 70;
private TextView logTextView;
public void addToLog(String str) {
if (str.length() > 0) {
errorLog.add( str) ;
}
// remove the first line if log is too large
if (errorLog.size() >= MAX_ERROR_LINES) {
errorLog.remove(0);
}
updateLog();
}
private void updateLog() {
String log = "";
for (String str : errorLog) {
log += str + "\n";
}
logTextView.setText(log);
}
Here is an example that adds lines to an output log limited by the set max lines. The scrollview will auto scroll to the bottom after every line is added. This example work purely with the contents of the TextView so it doesn't have the need for a separate data collection.
Add the following to your activity xml:
<ScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical" >
<TextView
android:id="#+id/textViewOutput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1000" />
</ScrollView>
In your activity add the following code:
private static final int MAX_OUTPUT_LINES = 50;
private static final boolean AUTO_SCROLL_BOTTOM = true;
private TextView _textViewOutput;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
_textViewOutput = (TextView) findViewById(R.id.textViewOutput);
}
//call to add line(s) to TextView
//This should work if either lineText contains multiple
//linefeeds or none at all
private void addLinesToTextView(String lineText) {
_textViewOutput.append(lineText);
removeLinesFromTextView();
if(AUTO_SCROLL_BOTTOM)
_scrollView.post(new Runnable() {
#Override
public void run() {
_scrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
});
}
// remove leading lines from beginning of the output view
private void removeLinesFromTextView() {
int linesToRemove = _textViewOutput.getLineCount() - MAX_OUTPUT_LINES;
if (linesToRemove > 0) {
for (int i = 0; i < linesToRemove; i++) {
Editable text = _textViewOutput.getEditableText();
int lineStart = _textViewOutput.getLayout().getLineStart(0);
int lineEnd = _textViewOutput.getLayout().getLineEnd(0);
text.delete(lineStart, lineEnd);
}
}
}
The TextView shows what you set via setText() method. So this sounds to me like you should cut down the input you provide.
To empty the TextView, you can do setText("");
Kotlin answer of Vincent Hiribarren
fun write_terminal_with_limit(data: String?, limit:Int)
{
log_textView.append(data)
val nb_line_to_del: Int = log_textView.lineCount - limit
// Erase excessive lines
if (nb_line_to_del > 0)
{
var end_of_line_idx = -1
val char_seq: CharSequence = log_textView.text
for (i in 0 until nb_line_to_del)
{
do
{
end_of_line_idx++
}
while (end_of_line_idx < char_seq.length && char_seq[end_of_line_idx] != '\n')
}
if (end_of_line_idx < char_seq.length)
{
log_textView.editableText.delete(0, end_of_line_idx + 1)
}
else
{
log_textView.text = ""
}
}
}
I made personnal adjustment...
I think you are using TextView.append(string) then it will add to old text.
If you are setting using setText it will replace the old text
This is an old one, but I just found looking for a solution to my own problem.
I was able to remove all TextViews from a LinearLayout using nameoflayout.removeAllViews();
There is another method that will allow you to remove views from specified places in the layout using ints, it's: nameoflayout.removeViews(start, count); so I'm sure you could create a time out for how long textviews remain visible.
No, android API doesn't provide any functionally that delete oldest lines from textview automatically till API level 25. you need to do it logically.
Try to write a function that takes an old string on TextView and add new string to it, then get substring last strings that TextView capable. And set it to TextView. Something like this:
String str = textview.getText();
str += newstring;
int ln = str.length();
ln = ln-250;
if (ln<0) ln=0;
str = str.substring(ln);
textview.setText(str);
reference Vincent Hiribarren answer.
make it simple-->
TextView _debugTextView;
//if excess 20 lines keep new 200 chars
if(_debugTextView.getLineCount() >20) _debugTextView.getEditableText().delete(0,_debugTextView.getText().length()-200);