I want to toggle textView on click.
val targetView = findViewById<TextView>(R.id.targetText)
targetView.text = 'example'
targetView.setOnClickListener {
if (it.visibility == View.VISIBLE) {
it.visibility = View.INVISIBLE
} else {
it.visibility = View.VISIBLE
}
}
But once I clicked and visibility of text was changed to invisible, then I can not click this again.
Suggestion: How about creating a view behind the text and make use of the view for toggle triggering instead of text.
i.e. onViewClicked { toggleTextVisibility() }
Store the text of the textview in a temporary string. Instead of toggling the visibility, set the text to null and then back to what it was using the temp variable.
String final tempText = "your text"
then
targetView.setOnClickListener(new View.OnClickListener) {
#Override
public void onClick(View view){
if (view.getText() == null) {
view.setText(tempText);
} else {
view.setText(" ");
}
});
}
just make sure your textview on the layout properties has a set minWidth and not wrap_content as it will disappear when you set the text to null
I am a total beginner, I am wondering if anyone could help me out with the code. I am trying to make ideal daily water intake apps.
There will be only one edit text for user to input their weight and I want it to divide for example 0.024. Have button to calculate and then display the answer on screen.
public class WaterCalculate extends Activity {
//Declare textviews as fields, so they can be accessed throughout the activity.
EditText weightuser;
TextView tv4;
ImageButton calculate;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.water_calculate);
//Bind the EditText views
weightuser = (EditText)findViewById(R.id.weight);
tv4 = (TextView)findViewById(R.id.res);
calculate = (ImageButton)findViewById(R.id.calc);
calculate.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
calculate();
}
});
}
private void calculate() {
//get entered texts from the edittexts,and convert to integers.
Double value1 = Double.parseDouble(weightuser.getText().toString());
//do the calculation
Double calculatedValue = (value1/0.024);
//set the value to the textview, to display on screen.
tv4.setText(String.valueOf("You need " + calculatedValue + "\nliters of water per day" ));
}
}
When i run the apps the button to calculate its not working and it show the app has stopped. Appreciate for the help.
I thought the problem is in this line.
tv4.setText(String.valueOf("You need " + calculatedValue + "\nliters of water per day" ));
Give a try like this...
tv4.setText("You need "+Double.toString(calculatedValue)+"\nliters of water per day");
and also ensure that you catched the exceptions at necessary places like converting editText value into double.
Try the below code, am sure it will work, when you use click listener for button you should use View.Onclick
class WaterCalculate extends Activity {
// Declare textviews as fields, so they can be accessed throughout the
// activity.
EditText weightuser;
TextView tv4;
ImageButton calculate;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.water_calculate);
// Bind the EditText views
weightuser = (EditText) findViewById(R.id.weight);
tv4 = (TextView) findViewById(R.id.res);
calculate = (ImageButton) findViewById(R.id.calc);
calculate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
calculate();
}
});
}
private void calculate() {
// get entered texts from the edittexts,and convert to integers.
Double value1 = Double.parseDouble(weightuser.getText().toString());
// do the calculation
Double calculatedValue = (value1 / 0.024);
// set the value to the textview, to display on screen.
tv4.setText(String.valueOf("You need " + calculatedValue
+ "\nliters of water per day"));
}
}
I'm using Mariotti's CardsLib to create a list with Cards. I create cards (in a for loop) as shown below:
CustomCard aCard = new CustomCard(getActivity().getApplicationContext());
CardHeader aHeader = new CardHeader(getActivity().getApplicationContext());
aHeader.setTitle(item.getHeaderText());
aCard.addCardHeader(aHeader);
aCard.setSpannableMainTitle(true);
aCard.setmSsbTitle(CustomSpannableBuilderForHome.getSpannedText(item));
CardThumbnail thumbnail = new CardThumbnail(getActivity().getApplicationContext());
thumbnail.setDrawableResource(R.drawable.ic_launcher);
aCard.addCardThumbnail(thumbnail);
cards.add(0, aCard);
CustomCard is a class extending Card class. I created this class because I need to assign an SpannableStringBuilder instance, instead of simple String. This is CustomCard:
public class CustomCard extends Card {
protected boolean isSpannableMainTitle;
/**
* Main Title
*/
protected SpannableStringBuilder mSsbTitle;
public SpannableStringBuilder getmSsbTitle() {
return mSsbTitle;
}
public void setmSsbTitle(SpannableStringBuilder mSsbTitle) {
this.mSsbTitle = mSsbTitle;
}
public boolean isSpannableMainTitle() {
return isSpannableMainTitle;
}
public void setSpannableMainTitle(boolean isSpannableMainTitle) {
this.isSpannableMainTitle = isSpannableMainTitle;
}
public CustomCard(Context context) {
super(context);
}
#Override
public void setupInnerViewElements(ViewGroup parent, View view) {
//Add simple title to header
if (view != null) {
TextView mTitleView = (TextView) view.findViewById(R.id.card_main_inner_simple_title);
if (mTitleView != null)
{
mTitleView.setText(isSpannableMainTitle? mSsbTitle : mTitle);
if (isSpannableMainTitle) mTitleView.setMovementMethod(LinkMovementMethod.getInstance());
}
}
}
}
Everything worked fine prior to using maps api V2. Today, the card's title does not appear when the text does not contain spans. If it does have spans, only spans are shown. It is also worth mentioning that the title to be set, is ALWAYS an instance of SpannableStringBuilder.
For example:
Text1 = This is a text with no spans
Text2 = This is a (text) with (spans) <--- where () denote the presence of span.
This is the output:
Card 1:
Picture + Header + no text
Card 2:
Picture + Header + (text) (spans)
That is, the first card has no text, while the latter displays only spanned text (i.e. This is a with, all of them ignored).
As I said, this behavior started once I included Maps API V2. Please help!
I'm using Talkback to read the content of the views on my ViewPager, and it's reading the content of the current view and the content of the next view (not visible).
For example
View 1
TextView -> hi1
TextView -> bye1
View2
TextView -> hi2
TextView -> bye2
Talkback read hi1, hi2, bye1, bye2
I've tried to change the value of pager.setOffscreenPageLimit(), but it doesn't do anything, Talkback always read the current view and the next one, even if the value of OffScreenPageLimit is 4 (it should read the next 2 views).
The only info I've found is that: https://code.google.com/p/eyes-free/issues/detail?id=139
Any idea?
You can create event custom Accessibility event inside the OnChangePageView and save the string you want to read in a list and get position from interface between Activity/fragment and adapter.
ViewPager.OnPageChangeListener pageChangeListener = new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrollStateChanged(int arg0) { }
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) { }
#Override
public void onPageSelected(int position) {
if(isTalkbackActive(getApplicationContext())) {
AccessibilityEvent event = AccessibilityEvent.obtain();
if (onPageChangeInterface != null) {
String text = onPageChangeInterface.getTextToRead(position);
event.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
event.getText().add(text);
viewPagerWallets.requestFocus();
viewPagerWallets.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
accessibilityManager.sendAccessibilityEvent(event);
}
}
}
};
Then the same string that you saved you add it in ContentDescription of the relative that you have all the view only in the first position.
ArrayList readAccessibilityValues = new ArrayList<>();
String valor = valor + txtView1.getText()+",";
valor = valor + txtView2.getText()+",";
if(position == 0) {
relativeGeneral.setContentDescription(valor);
}
readAccessibilityValues.add(valor);
I think it's not the best solution but I have not found another
This could help you to get into the right direction:
pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
val event = AccessibilityEvent.obtain()
event.eventType = AccessibilityEvent.TYPE_ANNOUNCEMENT
event.text.add("Hello TalkBack!")
val accessibilityManager = requireContext().getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
accessibilityManager.sendAccessibilityEvent(event)
}
})
Simply replace "Hello Talkback!" by any string you would like to be read when changing a page in ViewPager.
I have a multi-line TextView that has android:ellipsize="end" set. I would like to know, however, if the string I place in there is actually too long (so that I may make sure the full string is shown elsewhere on the page).
I could use TextView.length() and find about what the approximate length of string will fit, but since it's multiple lines, the TextView handles when to wrap, so this won't always work.
Any ideas?
You can get the layout of the TextView and check the ellipsis count per line. For an end ellipsis, it is sufficient to check the last line, like this:
Layout l = textview.getLayout();
if (l != null) {
int lines = l.getLineCount();
if (lines > 0)
if (l.getEllipsisCount(lines-1) > 0)
Log.d(TAG, "Text is ellipsized");
}
This only works after the layout phase, otherwise the returned layout will be null, so call this at an appropriate place in your code.
textView.getLayout is the way to go but the problem with that is that it returns null if layout is not prepared. Use the below solution.
ViewTreeObserver vto = textview.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Layout l = textview.getLayout();
if ( l != null){
int lines = l.getLineCount();
if ( lines > 0)
if ( l.getEllipsisCount(lines-1) > 0)
Log.d(TAG, "Text is ellipsized");
}
}
});
Code snippet for removing the listener (source):
mLayout.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
scrollToGridPos(getCenterPoint(), false);
mLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
I think the easiest solution to this question is the following code:
String text = "some looooong text";
textView.setText(text);
boolean isEllipsize = !((textView.getLayout().getText().toString()).equalsIgnoreCase(text));
This code assumes that in your XML the TextView set a maxLineCount :)
This worked to me:
textView.post(new Runnable() {
#Override
public void run() {
if (textView.getLineCount() > 1) {
//do something
}
}
});
The most eloquent solution I have found (in Kotlin) is to create an extension function on TextView
fun TextView.isEllipsized() = layout.text.toString() != text.toString()
This is great because it doesn't require knowing what the full string is or worrying about how many lines the TextView is using.
TextView.text is the full text that it's trying to show, whereas TextView.layout.text is what's actually shown on the screen so if they are different it must be getting ellipsized
To use it:
if (my_text_view.isEllipsized()) {
...
}
public int getEllipsisCount (int line):
Returns the number of characters to be ellipsized away, or 0 if no ellipsis is to take place.
So, simply call :
int lineCount = textview1.getLineCount();
if(textview1.getLayout().getEllipsisCount(lineCount) > 0) {
// Do anything here..
}
Since the getLayout() cant be called before the layout is set, use this:
ViewTreeObserver vto = textview.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Layout l = textview.getLayout();
if ( l != null){
int lines = l.getLineCount();
if ( lines > 0)
if ( l.getEllipsisCount(lines-1) > 0)
Log.d(TAG, "Text is ellipsized");
}
}
});
And finally do not forget to remove removeOnGlobalLayoutListener when you need it nomore.
lateinit var toggleMoreButton: Runnable
toggleMoreButton = Runnable {
if(reviewTextView.layout == null) { // wait while layout become available
reviewTextView.post(toggleMoreButton)
return#Runnable
}
readMoreButton.visibility = if(reviewTextView.layout.text.toString() != comment) View.VISIBLE else View.GONE
}
reviewTextView.post(toggleMoreButton)
It is some typical case:
comment in 'reviewTextView'
comment can collapsed by some criteria
if comment collapsed you show button 'readMoreButton'
The Kotlin way:
textView.post {
if (textView.lineCount > MAX_LINES_COLLAPSED) {
// text is not fully displayed
}
}
Actually View.post() is executed after the view has been rendered and will run the function provided
Simple Kotlin method. Allows android:ellipsize and android:maxLines to be used
fun isEllipsized(textView: TextView, text: String?) = textView.layout.text.toString() != text
Solution with kotlin extensions:
infoText.afterLayoutConfiguration {
val hasEllipsize = infoText.hasEllipsize()
...
}
Extensions:
/**
* Function for detect when layout completely configure.
*/
fun View.afterLayoutConfiguration(func: () -> Unit) {
viewTreeObserver?.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
viewTreeObserver?.removeOnGlobalLayoutListener(this)
func()
}
})
}
fun TextView.hasEllipsize(): Boolean = layout.getEllipsisCount(lineCount - 1) > 0
it is working for me
if (l != null) {
int lines = l.getLineCount();
if (lines > 0) {
for (int i = 0; i < lines; i++) {
if (l.getEllipsisCount(i) > 0) {
ellipsize = true;
break;
}
}
}
}
If your textview contains multiple paragraphs, using getEllipsisCount will not work for empty lines within it. getEllipsisCount for the last line of any paragraph will return 0.
Really work so, for example, to pass full data to dialog from item of RecyclerView:
holder.subInfo.post(new Runnable() {
#Override
public void run() {
Layout l = holder.subInfo.getLayout();
if (l != null) {
final int count = l.getLineCount();
if (count >= 3) {
holder.subInfo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final int c = holder.subInfo.getLineCount();
if (c >= 3) {
onClickToShowInfoDialog.showDialog(holder.title.getText().toString(), holder.subInfo.getText().toString());
}
}
});
}
}
}
});
Combining #Thorstenvv awnser with #Tiano fix, here is the Kotlin version :
val layout = textView.layout ?: return#doOnLayout
val lines = layout.lineCount
val hasLine = lines > 0
val hasEllipsis = ((lines - 1) downTo 0).any { layout.getEllipsisCount(it) > 0 }
if (hasLine && hasEllipsis) {
// Text is ellipsized
}
In Kotlin, you can use the below code.
var str= "Kotlin is one of the best languages."
textView.text=str
textView.post {
val isEllipsize: Boolean = !textView.layout.text.toString().equals(str)
if (isEllipsize) {
holder.itemView.tv_viewMore.visibility = View.VISIBLE
} else {
holder.itemView.tv_viewMore.visibility = View.GONE
}
}
This is simple library for creating textview expandable. Like Continue or Less. This library extended version TextView. Easy to use.
implementation 'com.github.mahimrocky:ShowMoreText:1.0.2'
Like this,
1 https://raw.githubusercontent.com/mahimrocky/ShowMoreText/master/screenshot1.png
2 https://raw.githubusercontent.com/mahimrocky/ShowMoreText/master/screenshot2.png
<com.skyhope.showmoretextview.ShowMoreTextView
android:id="#+id/text_view_show_more"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/text"
/>
In Activity you can use like:
ShowMoreTextView textView = findViewById(R.id.text_view_show_more);
//You have to use following one of method
// For using character length
textView.setShowingChar(numberOfCharacter);
//number of line you want to short
textView.setShowingLine(numberOfLine);
After researching I found the best way for me in Kotlin
To get the ellipsize status the textView must be rendered first, so we have to set the text first, then check the ellipsize logic inside textView.post scope
textView.text = "your text"
textView.post {
var ellipsized: Boolean = textView.layout.text.toString()).equalsIgnoreCase("your text"))
if(ellipsized){
//your logic goes below
}
}
Using getEllipsisCount won't work with text that has empty lines within it. I used the following code to make it work :
message.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
if(m.isEllipsized == -1) {
Layout l = message.getLayout();
if (message.getLineCount() > 5) {
m.isEllipsized = 1;
message.setMaxLines(5);
return false;
} else {
m.isEllipsized = 0;
}
}
return true;
}
});
Make sure not to set a maxLineCount in your XML. Then you can check for the lineCount in your code and if it is greater than a certain number, you can return false to cancel the drawing of the TextView and set the line count as well as a flag to save whether the text view is too long or not. The text view will draw again with the correct line count and you will know whether its ellipsized or not with the flag.
You can then use the isEllipsized flag to do whatever you require.
create a method inside your TextViewUtils class
public static boolean isEllipsized(String newValue, String oldValue) {
return !((newValue).equals(oldValue));
}
call this method when it's required eg:
if (TextViewUtils.isEllipsized(textviewDescription.getLayout().getText().toString(), yourModelObject.getDescription()))
holder.viewMore.setVisibility(View.VISIBLE);//show view more option
else
holder.viewMore.setVisibility(View.GONE);//hide
but textView.getLayout() can't call before the view(layout) set.