Hi all,
I'm banging my head with a problem that seems intractable to me (perhaps my ignorance x).
I have a TextView in which a string when I write, I calculate the space available and if necessary I reduce the font size to a minimum size set, then add a line and keep writing.
PROBLEM:
Writing strings of buttons 2 and 3, display the lines of the TextView are filled in correctly: the first line is complete and the rest of the string goes on the second line.
ES.:
56688+(555556565555566
555555
56688x(555556565555566
555555
Writing strings of buttons 1 and 4, show the lines of the TextView are filled incorrectly:
the first line is filled up to the '/' or '-' remained largely empty, and the text after the character is on the second line.
ES.:
56688/
(555556565555566555555
56688-
(555556565555566555555
The intended behavior is that of the strings of the buttons 2 and 3.
I can not understand why it behaves abnormally in the presence of the characters '/' and '-', and how to remedy this anomaly.
I enclose code:
In the file "activity_main.xml" I have a custom component that I report below:
<LinearLayout android:id="#+id/mainLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
androidrientation="vertical"
android:layout_alignParentTop="true">
<com.example.component.NumTextView
android:id="#+id/textViewInput"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:gravity="right"
android:maxHeight="64dp"
android:minHeight="64dp"
app:lines="1"
app:maxLines="3"
app:mintextsize="16"
app:maxtextsize="48"
androidadding="0dp"
android:scrollbars="vertical"
android:singleLine="false" android:text="" />
<View android:layout_width="fill_parent"
android:layout_height="1dp"
android:background="#000000" />
In the class "NumTextView" that inherits from "TextView" I have the following code:
private void refitText(String text, int textWidth)
{
float trySize = 23;
if( textWidth > 0 )
{
int lineCount = this.getLineCount();
this.setLines(lineCount + 1);
this.setVerticalScrollBarEnabled(true);
this.setMovementMethod(ScrollingMovementMethod.get Instance());
this.setTextSize(trySize);
}
}
#Override
protected void onTextChanged(final CharSequence text, final int start, final int before, final int after)
{
refitText( text.toString(), this.getWidth() );
}
Finally, in "MainActivity" I have the following code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textInput = (NumTextView) findViewById(R.id.textViewInput);
}
public void onClick1(View v)
{
String stringa ="56688-(555556565555566555555";
textInput.setText(stringa);
}
public void onClick2(View v)
{
String stringa ="56688+(555556565555566555555";
textInput.setText(stringa);
}
public void onClick3(View v)
{
String stringa ="56688x(555556565555566555555";
textInput.setText(stringa);
}
public void onClick4(View v)
{
String stringa ="56688/(555556565555566555555";
textInput.setText(stringa);
}
Why:
The slash(/) and hyphen(-) are breaking characters, so it will naturally seek to break the lines at those points. That's how word wrap works, by looking for breaking chars and inserting new line characters at the last break spot that will fit.
Fix?
If you can measure the lines to see how many characters will fit on each line, you may be able to insert a zero-width space(U+200B) to force a line break at that spot. Not all fonts support this character, however, so this may not work on all devices.
Various answers to this question may help you if you're unable to use a zw-space, or if you're interested in auto-sizing in general.
Related
I need to set prompt for my TextView, if String is too long to fit inside TV (i set max length 20) then it displays only part of it with "..." at the end. I want to display prompt with full String when i click on TV. Is it possible? And if yes then how to do it?
Inside activity:
textCompany.setText(testDb.getCompanyName(id));
textCompany.setEllipsize(null);
And XML:
<TextView
android:id="#+id/textCompany"
android:layout_width="match_parent"
android:layout_below="#+id/textId"
android:layout_height="wrap_content"
android:maxLength="20"
android:ellipsize="end"
android:gravity="end"
android:layout_marginEnd="20dp"
android:textSize="17sp"
android:text="verylongstringjusttotestifthisworksandletshopeitwill" />
You can do that with a simple onClickListener. First, you check what the length of the text is, then if it's more than 20 characters, you take the first 20 and add three dots to the end and display that. At the same time, you save the full text to a temporary variable, and you display it when someone clicks your TextView.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final TextView textView = findViewById(R.id.textCompany);
String shortMessage;
final String message = textView.getText().toString();
if(message.length() >= 20){
shortMessage = message.substring(0,19)+"...";
textView.setText(shortMessage);
}
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
}
});
}
Note: make sure you make your textView clickable by adding the following to your xml:
android:clickable="true"
The behavior you mentioned is due to
android:ellipsize="end"
It displays the end of text with "Some text..." if it does not fit in width.
You can programmatically change the ellipsize value to none to display the full text on Click.
myTextView.setEllipsize(null);
So, Does anybody know how to create following grid? I need to set clickable event to every word:
If four words are not fit to a line then should be shown three in a line:
if it will be exceed to a line n words then should be shown n words in a line.
Is there anybody knows how to implement this?
You can use SpannableString and ClickableSpan. this Activity, for example, creates TextView with your text and manages clicks on each word:
public class MainActivity extends AppCompatActivity {
Activity activity;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activity = this;
TextView textView = (TextView) findViewById(R.id.textView);
String text = "up down Antidisestablishment over took dropped lighten with from throught fell on up down Antidisestablishment over took dropped lighten with from throught fell on";
String[] textArray = text.split(" ");
SpannableString ss = new SpannableString(text);
int start = 0;
int end = 0;
for(final String item : textArray){
end = start + item.length();
ClickableSpan clickableSpan = new ClickableSpan() {
#Override
public void onClick(View textView) {
Toast.makeText(activity, "Say " + item+ "!", Toast.LENGTH_SHORT).show();
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
}
};
ss.setSpan(clickableSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
start += item.length()+1;
}
textView.setText(ss);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setHighlightColor(Color.TRANSPARENT);
}
}
and here is activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
android:padding="5dp">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textColor="#000000"
android:textColorLink="#000000"/>
</LinearLayout>
if you click on any word you get popup with this word
EDIT: to justify the text use the library android-justifiedtextview
But not the library from gradle, there are the old version which does not support SpannableString. I recommend just copy the class JustifyTextView from git to your project. Then you can use this view in your .xml like:
<com.yourdomain.yourproject.JustifyTextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textColor="#000000"
android:textColorLink="#000000"/>
here is what I got with this library:
you also can modify the library to keep last line unjustified. Every word in the text is still clickable.
If the amount of items you have to add is little, consider using a FlowLayout. It extends a LinearLayout, so just wrap it in a ScrollView, add your views to it dynamically, and you should be good to go.
In my activity is a TextView with the content "Ecl pse", where the "i" is missing. After I click on a button I want the letter "i" to appear in the right Position. But the "i" should be so animated, that it firstly appears a little bit bigger and then gets smaller until it is as big as the the other letters after I clicked on the button. But momentarily with my code the whole word "Ecl pse" is influenced by the ValueAnimation. It's not only that the "i" is bigger and gets smaller after I clicked on the button, but also the position of the whole word "Ecl pse" changes: "Ecl pse" goes down and then comes back in the origin position. How can i fix that? Again, I want only the letter "i" to appear a little bit bigger and then getting smaller until it is as big as the other letters of the word "Ecl pse" after I clicked on the button...
XML:
<?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" >
<TextView
android:id="#+id/tvhallo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="87dp"
android:text="Ecl pse"
android:textSize="70sp" />
<Button
android:id="#+id/BtnKlick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Klick" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/tvhallo"
android:layout_alignBottom="#+id/tvhallo"
android:layout_alignLeft="#+id/BtnKlick"
android:layout_toLeftOf="#+id/BtnKlick"
android:text="i"
android:textSize="70sp" />
</RelativeLayout>
CODE:
public Button btn;
public TextView tw;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.pagetwo);
btn = (Button) findViewById(R.id.BtnKlick);
tw = (TextView) findViewById(R.id.tvhallo);
btn.setOnClickListener(this);}
#SuppressLint("NewApi")
public void onClick(View v) {
// TODO Auto-generated method stub
ValueAnimator animator = new ValueAnimator();
animator.setDuration(2000);
animator.setObjectValues("Ecl pse", "Eclipse");
animator.setEvaluator(new TypeEvaluator<CharSequence>()
{
#Override
public CharSequence evaluate(float fraction, CharSequence startValue, CharSequence endValue)
{
float relativeSize = 4 - 3 * fraction;
Spannable span = new SpannableString("Eclipse");
span.setSpan(new RelativeSizeSpan(relativeSize), 3, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return span;
}
});
animator.addUpdateListener(new AnimatorUpdateListener()
{
#Override
public void onAnimationUpdate(ValueAnimator animation)
{
tw.setText((CharSequence)animation.getAnimatedValue());
}
});
animator.start();}}
I really doubt a TextView is the right instrument for what you're trying to achieve. It is both overkill and inadequate for the job. It can display all matters of text with various formatting and is for a good reason described as "a complete text editor". It's main purpose is to provide a way to display text, and possibly quite a lot of it (that part was the overkill). Inserting and (potentially) scaling the 'i' will cause the rest of the letters to move, as that is what the class is for. It's intended to layout text, not layout it statically in a way that causes changes to the content to move as little as possible (this is the inadequate part)
But what you actually want is not to display text, but an animation. I would recommend you create the text you want in any imaging program with various states: one without the 'i', a few with it too large and scaling down, and a final image with the correct proportions. Now use these images do display the animation triggered by pressing the button. I believe the correct class for this task would be AnimationDrawable, though I haven't used it myself. There are certainly numerous ways on how to get the exact behavior you want, but I hope this'll get you started!
I am creating an email form and would like to have text in an EditText that cannot be deleted. On the screenshot below, the To could not be deleted.
If anyone has suggestions on how to achieve the above, it would be great - Thanks.
My current code for the To EditText box:
<EditText
android:id="#+id/editText2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="0dp"
android:hint="#string/email_to" >
</EditText>
The problem is android:hint text dissappears when the user starts to text, and android:text can be deleted by the user.
How do we have text that cannot be deleted? Thanks.
Note:
Also, I would like to note that I have a method that clears text using a clear button - this works fine - but I am hoping that it would not delete the fixed text (If I got that implemented!).. Here`s the code for that:
private void clearForm(ViewGroup group)
{
for (int i = 0, count = group.getChildCount(); i < count; ++i) {
View view = group.getChildAt(i);
if (view instanceof EditText) {
((EditText)view).setText("");
}
if(view instanceof ViewGroup && (((ViewGroup)view).getChildCount() > 0))
clearForm((ViewGroup)view);
}
}
SOLUTION:
Managed a roundabout way of doing this.. I created a TextView and EditText within a nested Linear Layout. I turned off the border in the EditText using android:background="#00000000".
I created an xml file in the drawable folder, and refered to this in the relevant linear layout like this: android:background="#drawable/customxml"
You can do it by using Text Watcher listener.
You can keep text in edittext by checking length of edittext.
For example
editText.setText("To") // it mean have lenght 2
And Than in method afterTextChanged, check if text in editText is has been deleted (with check length of text in editText)
This is for complete example code:
editText.setText("To");
editText.addTextChangedListener(new TextWatcher() {
#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) {
if(s.length < 2){
editText.setText("To")//set editext with "To" again like has been initialized
editText.setSelection(editText.getText().length)// to make cursor in end of text
}
}
});
Hope this help!
To get the visual appearance you want, include a horizontal LinearLayout containing a text view and an EditView. Turn off the border around the EditView (there's an attribute that does that (I think it's android:shadowColor) ) Play around with margins and padding to get them to be adjacent to each other. Set the background color on the linear layout to put a border around the combined pair.
I wouldn't worry much about efficiency. You aren't nesting very deeply. The biggest challenge is going to be getting it to look like a single view.
Edit: Another thought. If that doesn't work, you could make the "To" a drawable, and set it using the android:drawableLeft attribute.
Add TextView to the right side of EditText in LinearLayout with horizontal orientation or RelativeLayout with android:layout_toRightOf="#id/YourTextView"
I wonder in case there is a ready implantation for textarea view that expand as user type more text. like the android built in SMS message text area.
I got a partial answer :) - i needed an SMS Style Textfield as well, so I made one myself, including a textwatcher that tracks how many characters are left.
This is what it will look like:
The Textwatcher implementation
public class SMSTextWatcher implements TextWatcher {
private final int maxLength;
private final int stringId;
private final TextView textView;
/**
* #param maxLength maximum number of characters that are allowed
* #param stringId must have at least one %s in it, for the updated character count.
* #param targetView target text view that displays the number of characters left.
*/
public SMSTextWatcher(int maxLength, int stringId, TextView targetView) {
this.maxLength = maxLength;
this.textView = targetView;
this.stringId = stringId;
updateTextView(maxLength);
}
#Override
public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence charSequence, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable editable) {
//Update textview (the limit is handled by the maxLength attribute)
updateTextView(maxLength - editable.length());
}
public void updateTextView(int charactersLeft) {
textView.setText(String.format(textView.getContext().getString(stringId), charactersLeft));
}
}
The Layout XML - let's call it widget_sms_field.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="#+id/sms_field_text"
style="#style/TextAppearance.AppCompat.Large"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:hint="#string/short_text"
android:imeOptions="actionSend|flagNoEnterAction"
android:inputType="textShortMessage|textAutoCorrect|textCapSentences|textMultiLine"
android:maxLength="#integer/sms_text_max_length"
android:paddingRight="10dp"
android:singleLine="false" />
<TextView
android:id="#+id/sms_field_remaining_characters"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:text="#string/remaining_characters"
android:textColor="#color/secondary_text" />
</LinearLayout>
The Max Length
In above layout file we used android:maxLength="#integer/sms_text_max_length"
to resolve it, we'll have to create a file called "integer.xml" in the values folder of your project. The content of the file should be as follows:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="sms_text_max_length" type="integer">160</item>
</resources>
If you name the file something other than "integer" - make sure to also change the #integer/sms_text... accordingly.
The "x characters left" Text
The little grey-colored text field(#color/secondary_text - you need to create this color yourself!) with the id sms_field_remaining_characters is the field which will display how many characters are left. For this purpose create a new string resource:
<string name="remaining_characters">%s remaining Characters</string>
Include the widget layout xml in your own layout and in your Fragment's onViewCreated method link the SMSTextWatcher to our sms-style field:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
EditText textField = (EditText) view.findViewById(R.id.sms_field_text);
textField.addTextChangedListener(new SMSTextWatcher(
getResources().getInteger(R.integer.sms_text_max_length),
R.string.remaining_characters,
(TextView) view.findViewById(R.id.sms_field_remaining_characters)));
}
Done :) ! Let me know, if you have questions or suggestions!