I am trying to teach myself Android Java programming and I have started by attempting to create a simple text editor.
I wanted to have a line count down the left hand side like standard IDEs, and I couldn't really find anywhere on StackExchange or the internet on the definitive "best practice" way to do something like this.
So I created my own logic based on what I read, but I wanted to just check that this was the best and most efficient way to do it -- and also if this happens to help anyone out looking to do the same thing.
// START onCreate
// #mEditText = Main AutoCompleteTextView
// #mLineCount = Line Count TextView
mEditText.addTextChangedListener(new TextWatcher() {
// Set current line variable
private int currentLine;
// Text Watcher
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Before new text is inserted, get the current line count
currentLine = mEditText.getLineCount();
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Do nothing
}
#Override
public void afterTextChanged(Editable e) {
// Update Line Count
// #mEditText: AutoCompleteTextView Input
// #mLineCount: TextView Output
// #currentLine: Integer
updateLineCount(mEditText, mLineCount, currentLine);
}
});
// END onCreate
public void updateLineCount(AutoCompleteTextView editText, TextView lineText, int currentLine){
// Get updated Line Count
int lineCount = editText.getLineCount();
// If that Line Count exists and IS NOT the "before" Line Count (to stop repeating)
if(lineCount > 0 && lineCount != currentLine){
// If "before" Line Count is smaller, push Line Count up
if(currentLine < lineCount){
lineText.append(Integer.toString(lineCount) + "\n");
}
// Else if "before" Line Count is greater (ie. you have deleted a line), push Line Count down
else {
// Get Text of current lineText TextView, replace with a substring of
// the current lineText TextView - the length of the deleted line
// (ie. Line 9 = 1 Character + 1 for the line break; Line 10 = 2 Characters + 1 etc)
lineText.setText(lineText.getText().toString().substring(0, lineText.getText().toString().length() - (Integer.toString(lineCount+1).length() + 1)));
}
}
return;
}
So yeah, this is working fine -- but I am especially not sure about that last line -- Seems abit ... resource wasteful .. to be replacing the entire lineText TextView content each time a line is deleted.
Is there an anti-append that might work better in this situation?
Thanks,
Jamie
if(lineCount > 0 && lineCount != currentLine){
What happend if I select all text and delete all.
That will not meet the condition. So, mabe text line still display "5 lines" rather than "0 line"
Related
I have an editText box and when user writes "hello" I want only change "hello" font-family change to italic but others text font-family stay same only change "hello"
String detectText, text;
detectText = "hello";
text = title.getText().toString();
detectText.
Could you please help me?
As someone said, you need a text watcher to be able to make changes when the text is changed. You also need spans to be able to style parts of the text. Here's a way to do it:
editText.addTextChangedListener(new TextWatcher() {
private static final String KEYWORD = "hello";
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
#Override
public void afterTextChanged(Editable s) {
// Remove previous spans.
for (StyleSpan span : s.getSpans(0, s.length(), StyleSpan.class)) {
s.removeSpan(span);
}
// Add new spans for every occurrence of the keyword.
int i = 0;
while (i != -1) {
i = text.toString().indexOf(KEYWORD, i);
if (i != -1) {
s.setSpan(new StyleSpan(Typeface.ITALIC), i, i + KEYWORD.length(),
Spannable.SPAN_INCLUSIVE_INCLUSIVE);
i += KEYWORD.length();
}
}
}
});
The text watcher has three methods called at different times of the editing, but it's only safe to make changes to the text in afterTextChanged. There, all previous style spans are removed then the text is scanned to add new ones.
Note that performance might be a problem if you intend to turn this into something a lot more complex, like a syntax highlighter. Right now all spans get readded everytime the user changes a single character.
This question already has answers here:
How to Delete Item Without Deleting Position in Recycler View?
(2 answers)
Closed 4 years ago.
I am trying to count clicks based on getAdapterPosition(). And it works properly. Below the code
#Override
public void onClick(View v) {
// Do button click handling here
if ( posisi2==getAdapterPosition() ) {
clickcount--;
tombolbaca.setText("Baca " + clickcount + "x");
if (clickcount <= 0)
{
mTitle.setVisibility(View.GONE);
rl2.setVisibility(View.GONE);
}
} // adapter
} // onClick
But when I am trying to count clicks using the comparison of two string, I got the problem. The result is, the computer can only count that once. Can you help me to fix the problem? The problem lays here:
public Button tombolbaca;
private int klik10 = 10;
#Override
public void onClick(View v) {
tombolbaca = (Button) v.findViewById(R.id.buttonbaca);
// Problem here
if( tombolbaca.getText().toString().equals("Baca 10x") ) {
klik10--;
tombolbaca.setText("Baca " + klik10 + "x");
if (klik10 <= 0)
{
mTitle.setVisibility(View.GONE);
rl2.setVisibility(View.GONE);
}
}
} // onclick
Ok, got it now.
The problem is in logics: this is your code, written by text instead of code
if( tombolbaca.getText().toString().equals("Baca 10x"){ // this line says "if the text is exactly Baca 10x, go on"
klik10--; // this line says: "make the value of klik10 = klik10 -1
tombolbaca.setText("Baca " + klik10 + "x"); //this line says "set text of tombolbaca as the composition of the strings and the value of klik10
if (klik10 <= 0) //if klik10 is equal or less than 0, do this
{
mTitle.setVisibility(View.GONE);
rl2.setVisibility(View.GONE);
}
So, the problem lays here:
First iteration:
klik10 = 10
it enter the first if
klik10 will now be 9
text will be Baca 9x
not less than 1, so skip the if
Second iteration
klik10 = 9 (because you set it before)
not going into if
so, the problem is that you are going in only if text is Baca 10x, but after the first iteration it won't be that anymore.
A solution could be this:
#Override
public void onClick(View v) {
klik10--;
tombolbaca.setText("Baca " + klik10 + "x");
if (klik10 <= 0)
{
mTitle.setVisibility(View.GONE);
rl2.setVisibility(View.GONE);
}
}
The if, as it is written, is not necessary. you can just remove it and the code will work.
If not, tell me why there is the if clause and I will fix above code :)
PS:
If you want to check if the text is the correct counter, do the following if:
if(tombolbaca.getText().String().equals("Baca " + klik10.toString() + "x"){
...
In second attempt the comparation will be between "Baca 9x".equals("Baca 10x") and your if statement not will work
Try as follow
if( !tombolbaca.getText().toString().equals("Baca 0x") ) { //using "Baca 0x"
...
}
i have set some text in JTextArea. The cursor is in 5th line. Now I want to set some text in the first line.
So is it possible to re position the cursor to desired line?
Use JTextComponent.setCaretPosition(int) which:
Sets the position of the text insertion caret for the TextComponent. Note that the caret tracks change, so this may move if the underlying text of the component is changed. If the document is null, does nothing. The position must be between 0 and the length of the component's text or else an exception is thrown.
If you want to go from one actual text line to another text line then you still need to use the JTextComponent.setCaretPosition() method but what you will also need is a means to get the desired line starting index to pass to the JTextComponent.setCaretPosition() method. Here is how you can get the starting index of any supplied line number providing the line number supplied exists within the document:
public int getLineStartIndex(JTextComponent textComp, int lineNumber) {
if (lineNumber == 0) { return 0; }
// Gets the current line number start index value for
// the supplied text line.
try {
JTextArea jta = (JTextArea) textComp;
return jta.getLineStartOffset(lineNumber-1);
} catch (BadLocationException ex) { return -1; }
}
How you might use the above method (let's say from the ActionPerformed event of a JButton):
int index = getLineStartIndex(jTextArea1, 3);
if (index != -1) {
jTextArea1.setCaretPosition(index);
}
jTextArea1.requestFocus();
The example usage code above will move the caret (from whatever location it happens to be in within the document) to the beginning of line 3 within the same document.
EDIT: Based on question in comments...
To move the caret to the end of a line you can make yet another method very similar to the getLineStartIndex() method above except now we'll name it getLineEndIndex() and we'll make a single code line change:
public int getLineEndIndex(JTextComponent textComp, int lineNumber) {
if (lineNumber == 0) { return 0; }
// Gets the current line number end index value for
// the supplied text line.
try {
JTextArea jta = (JTextArea) textComp;
return jta.getLineEndOffset(lineNumber-1) - System.lineSeparator().length();
} catch (BadLocationException ex) { return -1; }
}
Use this method the same way as the getLineStartIndex() method shown above.
Have an assignment I cant figure out. The assignment is:
With a given method:
static void writeTexts(String text, int amount);
Print out the text in the parameter text as many times as given by the variable amount. Every print of text on separate line.
Print an empty line for every third time text is printed.
Write a main method with one or more calls of writeTexts with appropriate test data (don't know what this means) to check that the method works in all cases.
I'm a beginner and find this very difficult, have been reading and watching tutorials, also searched and found a similar question, but can`t seem to grasp this. Any help is appreciated.
The error I get when running my code is:
cannot find symbol.
What I got so far:
public class Task {
static void writeTexts(String text, int amount) {
amount = 0;
text = "hallo";
while (amount< 3) {
System.out.println(text);
amount++;
}
}
public static void main(String[] args) {
writeTexts(text);
}
}
static void writeTexts(String text, int amount) {
for(int i = 0; i < amount; i++){
//Check if the line is the a multiple of 3
//then print an empty line
//I use i + 1 because I start at 0 which is a multiple of 3
//but we are not interested by the that
if( (i + 1) % 3 == 0 ){
System.out.println("");
}
//Print the text
System.out.println(text);
}
Now for calls of writeTexts with appropriate test data that essentially means call the function with so the appropriate parameters e.g: writeText("Halo 3", 3).
I would strongly recommend you to read some more on function to get better grasp of how they work.
You are overwriting amount with 0 and you are overwriting text with "hallo" which is incorrect because you will be printing "hallo" instead of text and you lose track of how many time you need to print.
amount = 0;
text = "hallo";
Your loop will always only iterate 3 times. Instead you should iterate amount times. To do this, you will also need a counter i
int i = 0;
while (i < amount) {
You are not printing an empty line every third time text is printed. You should add this:
i++;
if (amount % 3 == 0) { // If amount is divisible by 3
System.out.println();
}
I'm trying to implement iPhone like PIN-code authorization with 4 EditText blocks like this:
I'm using TextWatcher to check if field was changed so I can jump between blocks.
Here is the code:
#Override
public void afterTextChanged(Editable s) {
if (del && index > 0) {
pin[index - 1].requestFocus();
}
else if ( ! del && ind < 3) {
pin[index + 1].requestFocus();
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
del = count != 0;
}
Everything works fine except when block is empty and DEL/BACKSPACE is pressed, I want to go back to previous block and clear its' value.
This is where TextWatcher fails me since no change was made in empty block it doesn't do anything.
I have tried using keyEventListener but it only catches events on emulator not on actual device via virtual keyboard.
Can anyone suggest an idea of how can I catch DEL event or any other way to implement this?
Maybe you can check if the field is empty before and after change? Don't know if any other key press can leave the field empty and so you can say, back was pressed and jump to previous field. Ok this is not a real technical solution, but just a different way of viewing the problem.
I found a workaround for this issue. This is probably not the best solution, but it works for me.
Aside from TextWatcher I've added InputFilter to blocks
#Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
if ( end == 0 && ind > 0 && dest.length() == 0 ) {
pin[ind - 1].requestFocus();
}
return null;
}
I also think it's a better idea to port the rest of the code from TextWatcher to InputFilter