I have not understood how to return values from the method below, I have tried to return int but it shows me a weird error which is not possible to solve. This is the code:
private void showTheEnemy() {
ViewTreeObserver vto = radarImage.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
radarImage.getViewTreeObserver().removeOnPreDrawListener(this);
yradar_height = radarImage.getMeasuredHeight();
xradar_width = radarImage.getMeasuredWidth();
return true;
}
});
coordinateText.setText(yradar_height + " " + xradar_width);
}
I have understood that values are not being updated in the method because when I use setText() method then int values are 0.
You get zeros because the inner-method is not triggered before you set the text. The values are set at whatever they were when you last initialized them.
Set the text from the callback.
private TextView coordinateText;
private int xradar_width = 0;
private int yradar_height = 0;
private void showTheEnemy() {
ViewTreeObserver vto = radarImage.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
yradar_height = radarImage.getMeasuredHeight();
xradar_width = radarImage.getMeasuredWidth();
coordinateText.setText(String.format("%d %d",
yradar_height,
xradar_width
));
radarImage.getViewTreeObserver().removeOnPreDrawListener(this);
return true;
}
});
// Your values are still 0 here
}
Or pass to another method.
private TextView coordinateText;
private void showTheEnemy() {
ViewTreeObserver vto = radarImage.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
setCoordinate(coordinateText,
radarImage.getMeasuredHeight(),
radarImage.getMeasuredWidth() ));
radarImage.getViewTreeObserver().removeOnPreDrawListener(this);
return true;
}
});
}
private static void setCoordinate(TextView tv, int xPos, int yPos) {
tv.setText(String.format("%d %d", xPos, yPos));
}
Set values when you get radarImage width and height:
private void showTheEnemy() {
ViewTreeObserver vto = radarImage.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
radarImage.getViewTreeObserver().removeOnPreDrawListener(this);
yradar_height = radarImage.getMeasuredHeight();
xradar_width = radarImage.getMeasuredWidth();
coordinateText.setText(yradar_height + " " + xradar_width);
return true;
}
});
coordinateText.setText(yradar_height + " " + xradar_width);
}
EDIT:
Create class fields and when new values are provided pass those values where you need them.
Related
I wrote a little STT-functionality, with a floating button that is pulsating after being clicked on to notify that the app is listening. This works quite well so far with the one annoying behavior that my floating button does not return to its original size in some cases.
The animation increases and decreases the size of the button, and I guess it gets stuck in the increased state, hence the randomness of this behavior. I just can't figure out how to catch that and set the size to the original one.
Action Listener of my Button:
private View.OnTouchListener setVoiceButtonOnClick()
{
return new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
if(!voiceButton.isInitialized())
voiceButton.initAnimationValues();
voiceButton.setPressed(true);
listen();
}
return true;
}
};
}
My Button extends FloatingActionButton, and does the following:
public class FloatingVoiceButton extends FloatingActionButton
{
public static final float DEFAULT_ANIMATION_FACTOR = 1.2f;
private boolean isInitialized = false;
private int originalHeight;
private int originalWidth;
private boolean isAnimationRunning;
private ObjectAnimator animator;
public FloatingVoiceButton(Context context)
{
super(context);
}
public void initAnimationValues()
{
isInitialized = true;
isAnimationRunning = false;
originalHeight = getMeasuredHeight();
originalWidth = getMeasuredWidth();
animator = ObjectAnimator.ofPropertyValuesHolder(
this,
PropertyValuesHolder.ofFloat("scaleX", DEFAULT_ANIMATION_FACTOR),
PropertyValuesHolder.ofFloat("scaleY", DEFAULT_ANIMATION_FACTOR));
animator.setDuration(200);
animator.setRepeatCount(ObjectAnimator.INFINITE);
animator.setRepeatMode(ObjectAnimator.REVERSE);
}
public boolean isInitialized()
{
return isInitialized;
}
public void resetButtonSize()
{
setMeasuredDimension(originalWidth, originalHeight);
}
public boolean isAnimationRunning()
{
return isAnimationRunning;
}
public void animate(boolean doAnimation)
{
isAnimationRunning = doAnimation;
if(doAnimation)
animator.start();
else
{
animator.end();
setPressed(false);
resetButtonSize();
//destroyDrawingCache(); tried these without success
//postInvalidate();
}
}
}
Finally I am controlling the button the start and end of the animation with my RecognitionListener:
public class InputVoiceRecognitionListener implements RecognitionListener
{
private EditText targetEditText;
private String originalContent;
private final String DELIMITER = "\n\n";
private FloatingVoiceButton button;
public InputVoiceRecognitionListener(EditText editText, FloatingVoiceButton button)
{
targetEditText = editText;
originalContent = editText.getText().toString();
this.button = button;
}
#Override
public void onReadyForSpeech(Bundle params)
{
button.animate(true);
}
#Override
public void onBeginningOfSpeech()
{
originalContent = targetEditText.getText().toString();
}
#Override
public void onRmsChanged(float rmsdB)
{}
#Override
public void onBufferReceived(byte[] buffer)
{}
#Override
public void onEndOfSpeech()
{
if(button.isAnimationRunning())
button.animate(false);
}
#Override
public void onError(int error)
{
if(button.isAnimationRunning())
button.animate(false);
}
#Override
public void onResults(Bundle results)
{
setRecognizedText(results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION));
}
#Override
public void onPartialResults(Bundle partialResults)
{
setRecognizedText(partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION));
}
#Override
public void onEvent(int eventType, Bundle params)
{
}
private void setRecognizedText(ArrayList<String> matches)
{
String result = "";
if(matches != null)
result = matches.get(0);
if((originalContent.trim()).length() > 0)
{
if(!originalContent.endsWith("\n\n"))
result = originalContent + DELIMITER + result;
else result = originalContent + result;
}
targetEditText.setText(result);
targetEditText.setSelection(result.length());
}
}
EDIT
This did it for me:
resettingAnimator = ObjectAnimator.ofPropertyValuesHolder(
this,
PropertyValuesHolder.ofFloat("scaleX", 1.0f),
PropertyValuesHolder.ofFloat("scaleY", 1.0f));
resettingAnimator.setDuration(0);
resettingAnimator.setRepeatCount(1);
and calling resettingAnimator.start(); when I finish my main animation.
Simple solution to this problem is that you define another animation after stopping your repeating one.
I just can't figure out how to catch that and set the size to the original one.
You, that is View, does know what is the "original" size, its the size of the scale factor 1f. So after stopping repeating animation just make another animations to set scale to 1f
PropertyValuesHolder.ofFloat("scaleX", 1f)
PropertyValuesHolder.ofFloat("scaleY", 1f))
This animation will run always, but will not be visible if your button is already at "normal" size.
With this in mind I would recommend that you use some other flag than isAnimationRunning(), either by some state (ex. selected) of your Fab, or some manually set arbitrary boolean.
I have been searching a lot of similar answer from here, but none can work accurately. I want to calculate the visible area of a custom view, the view can be blocked by the screen edge, or block by the edge of scroll view, let see the picture below:
As above, black color is my screen, red color is my custom view and scroll up a bit, I want to measure area of B.
As above, black color is my screen, red color is my custom view, blue color is scroll view. Custom view is child of the scroll view and it is scroll up a bit. I want to measure area of B.
1) I have tried, View.getWindowVisibleDisplayFrame, View.getLocalVisibleRect, View.getGlobalVisibleRect, but none of it work accurately. First glance they looks good, but when I scroll my view disappear from screen, somehow, it show me the full height and width of the view, which the view is not even displayed within the screen.
2) I tried View.getLocationOnScreen() and getLocationInWindow() to calculate the offset manually, get XY coordination and plus/minus the view's (and screen) height and width, but found it not easy too, because the top of screen always have extra menu bar or etc, and will mess out with the result.
3) Although this is not likely in my situation, I want to know, if there is a absolute layout on top of my view and partially block it, can I still find out the area? (both layout are in same activity)
My question is, is there any easy and accurate way to calculate the area I want?
Ok, I found the answer from one of the open source Ad framework:
/**
* Whether the view is at least certain % visible
*/
boolean isVisible(#Nullable final View rootView, #Nullable final View view, final int minPercentageViewed) {
// ListView & GridView both call detachFromParent() for views that can be recycled for
// new data. This is one of the rare instances where a view will have a null parent for
// an extended period of time and will not be the main window.
// view.getGlobalVisibleRect() doesn't check that case, so if the view has visibility
// of View.VISIBLE but it's group has no parent it is likely in the recycle bin of a
// ListView / GridView and not on screen.
if (view == null || view.getVisibility() != View.VISIBLE || rootView.getParent() == null) {
return false;
}
if (!view.getGlobalVisibleRect(mClipRect)) {
// Not visible
return false;
}
// % visible check - the cast is to avoid int overflow for large views.
final long visibleViewArea = (long) mClipRect.height() * mClipRect.width();
final long totalViewArea = (long) view.getHeight() * view.getWidth();
if (totalViewArea <= 0) {
return false;
}
return 100 * visibleViewArea >= minPercentageViewed * totalViewArea;
}
I made a mistake while I am using View.getGlobalVisibleRect, when the view disappear from the screen, this method will return false, although the mClipRect object still providing value. Above is the correct way in using it.
During implementing a new feature "ViewHierarchy" in my work at Instabug I face the same problem and fix this problem through the below code
This is util class that does all the logic
public class ViewFrameInspector {
private static final String KEY_X = "x";
private static final String KEY_Y = "y";
private static final String KEY_W = "w";
private static final String KEY_H = "h";
/**
* Method emit inspected ViewFrame of passed view, the emit ViewFrame contains inspected ViewFrames fot its children and children of the children and so on
* by converting the emitted ViewFrame to list of View Frames you can find the a specific view and its frame with easily way
*
* #param view the root view
* #return return ViewFrame observable
*/
public static Observable<ViewFrame> inspectRootViewFrameRx(final View view) {
return Observable.defer(new Func0<Observable<ViewFrame>>() {
#Override
public Observable<ViewFrame> call() {
ViewFrame rootViewFrame = new ViewFrame();
rootViewFrame.setRoot(true);
rootViewFrame.setView(view);
return Observable.just(inspectVisibleViewFrame(rootViewFrame));
}
});
}
private static ViewFrame inspectVisibleViewFrame(final ViewFrame viewFrame) {
if (viewFrame.getView().getVisibility() == View.VISIBLE)
try {
viewFrame.setId(inspectViewResourceId(viewFrame.getView().getContext(), viewFrame.getView().getId()));
viewFrame.setType(ViewFrameInspector.inspectViewType(viewFrame.getView()));
viewFrame.setOriginalRect(ViewFrameInspector.inspectViewOriginalRect(viewFrame.getView()));
viewFrame.setVisibleRect(ViewFrameInspector.inspectViewVisibleRect(viewFrame));
viewFrame.setFrame(ViewFrameInspector.inspectViewFrame(viewFrame));
// inspect view children if exist
if (viewFrame.getView() instanceof ViewGroup) {
viewFrame.setHasChildren(true);
inspectViewChildren(viewFrame);
} else {
viewFrame.setHasChildren(false);
}
} catch (JSONException e) {
Log.e(ActivityViewInspector.class.getSimpleName(), "inspect view frame got error: " + e.getMessage() + ",view id:" + viewFrame.getId() + ", time in MS: " + System.currentTimeMillis(), e);
}
return viewFrame;
}
private static void inspectViewChildren(ViewFrame parentViewFrame) throws JSONException {
if (parentViewFrame.getView() instanceof ViewGroup) {
ViewGroup parent = (ViewGroup) parentViewFrame.getView();
for (int i = 0; i < parent.getChildCount(); i++) {
ViewFrame childViewFrame = new ViewFrame();
childViewFrame.setRoot(false);
childViewFrame.setView(parent.getChildAt(i));
childViewFrame.setParent(parentViewFrame);
parentViewFrame.addNode(inspectVisibleViewFrame(childViewFrame));
}
}
}
private static String inspectViewType(View view) {
return view.getClass().getSimpleName();
}
private static String inspectViewResourceId(Context context, int id) throws JSONException {
try {
return context != null && context.getResources() != null && context.getResources().getResourceEntryName(id) != null ?
context.getResources().getResourceEntryName(id) : String.valueOf(id);
} catch (Resources.NotFoundException e) {
return String.valueOf(id);
}
}
private static Rect inspectViewOriginalRect(View view) {
int[] locationOnScreen = new int[2];
view.getLocationOnScreen(locationOnScreen);
return new Rect(locationOnScreen[0],
locationOnScreen[1],
locationOnScreen[0] + view.getWidth(),
locationOnScreen[1] + view.getHeight());
}
private static Rect inspectViewVisibleRect(ViewFrame viewFrame) {
if (viewFrame.isRoot()) {
return viewFrame.getOriginalRect();
} else {
Rect viewVisibleRect = new Rect(
viewFrame.getOriginalRect().left,
viewFrame.getOriginalRect().top,
viewFrame.getOriginalRect().right,
viewFrame.getOriginalRect().bottom);
Rect parentAvailableVisibleRect = new Rect(
inspectViewAvailableX(viewFrame.getParent()),
inspectViewAvailableY(viewFrame.getParent()),
inspectViewAvailableRight(viewFrame.getParent()),
inspectViewAvailableBottom(viewFrame.getParent()));
if (viewVisibleRect.intersect(parentAvailableVisibleRect)) {
return viewVisibleRect;
} else {
return new Rect(0, 0, 0, 0);
}
}
}
private static int inspectViewAvailableX(ViewFrame viewFrame) {
int visibleLeft, paddingLeft, originalLeft;
visibleLeft = viewFrame.getVisibleRect().left;
paddingLeft = viewFrame.getView().getPaddingLeft();
originalLeft = viewFrame.getOriginalRect().left;
if (paddingLeft == 0) {
return visibleLeft;
} else {
if (visibleLeft > (originalLeft + paddingLeft)) {
return visibleLeft;
} else {
return originalLeft + paddingLeft;
}
}
}
private static int inspectViewAvailableY(ViewFrame viewFrame) {
int visibleTop, paddingTop, originalTop;
visibleTop = viewFrame.getVisibleRect().top;
paddingTop = viewFrame.getView().getPaddingTop();
originalTop = viewFrame.getOriginalRect().top;
if (paddingTop == 0) {
return visibleTop;
} else {
if (visibleTop > (originalTop + paddingTop)) {
return visibleTop;
} else {
return originalTop + paddingTop;
}
}
}
private static int inspectViewAvailableRight(ViewFrame viewFrame) {
int visibleRight, paddingRight, originalRight;
visibleRight = viewFrame.getVisibleRect().right;
paddingRight = viewFrame.getView().getPaddingRight();
originalRight = viewFrame.getOriginalRect().right;
if (paddingRight == 0) {
return visibleRight;
} else {
if (visibleRight < (originalRight - paddingRight)) {
return visibleRight;
} else {
return originalRight - paddingRight;
}
}
}
private static int inspectViewAvailableBottom(ViewFrame viewFrame) {
int visibleBottom, paddingBottom, originalBottom;
visibleBottom = viewFrame.getVisibleRect().bottom;
paddingBottom = viewFrame.getView().getPaddingBottom();
originalBottom = viewFrame.getOriginalRect().bottom;
if (paddingBottom == 0) {
return visibleBottom;
} else {
if (visibleBottom < (originalBottom - paddingBottom)) {
return visibleBottom;
} else {
return originalBottom - paddingBottom;
}
}
}
private static JSONObject inspectViewFrame(ViewFrame viewFrame) throws JSONException {
return new JSONObject().put(KEY_X, viewFrame.getVisibleRect().left)
.put(KEY_Y, viewFrame.getVisibleRect().top)
.put(KEY_W, viewFrame.getVisibleRect().width())
.put(KEY_H, viewFrame.getVisibleRect().height());
}
public static List<ViewFrame> convertViewHierarchyToList(ViewFrame viewFrame) {
ArrayList<ViewFrame> viewFrameHierarchies = new ArrayList<>();
if (viewFrame != null) {
viewFrameHierarchies.add(viewFrame);
if (viewFrame.hasChildren()) {
for (ViewFrame childViewHierarchy : viewFrame.getNodes()) {
viewFrameHierarchies.addAll(convertViewHierarchyToList(childViewHierarchy));
}
}
}
return viewFrameHierarchies;
}
}
This is model class that hold all data related to inspected views
public class ViewFrame {
private String id;
private String type;
private JSONObject frame;
private ViewFrame parent;
private ArrayList<ViewFrame> nodes;
private boolean hasChildren;
private boolean isRoot;
private Rect originalRect;
private Rect visibleRect;
private View view;
public ViewFrame() {
nodes = new ArrayList<>();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public JSONObject getFrame() {
return frame;
}
public void setFrame(JSONObject frame) {
this.frame = frame;
}
public ViewFrame getParent() {
return parent;
}
public void setParent(ViewFrame parent) {
this.parent = parent;
}
public ArrayList<ViewFrame> getNodes() {
return nodes;
}
public void addNode(ViewFrame childViewHierarchy) {
nodes.add(childViewHierarchy);
}
public boolean hasChildren() {
return hasChildren;
}
public void setHasChildren(boolean hasChildren) {
this.hasChildren = hasChildren;
}
public boolean isRoot() {
return isRoot;
}
public void setRoot(boolean root) {
isRoot = root;
}
public Rect getVisibleRect() {
return visibleRect;
}
public void setVisibleRect(Rect visibleRect) {
this.visibleRect = visibleRect;
}
public Rect getOriginalRect() {
return originalRect;
}
public void setOriginalRect(Rect originalRect) {
this.originalRect = originalRect;
}
public View getView() {
return view;
}
public void setView(View view) {
this.view = view;
}
}
Hope this code help you also
I know this is kind of a duplicate but the answers for other question didn't help me. always my ImageView height returns zero. here is what I tried:
dart.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
int finalHeight = dart.getMeasuredHeight();
int finalWidth = dart.getMeasuredWidth();
Toast.makeText(MainActivity.this," "+finalHeight,Toast.LENGTH_SHORT).show();
return true;
}
});
ALSO -
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
height = dart.getHeight();
width = dart.getWidth();
Toast.makeText(MainActivity.this," "+height,Toast.LENGTH_SHORT).show();
}
And I also tried dart.getHeight() inside the onCreate but I understood it can't work. What can I do?
Add addonPreDrawListener to ViewTreeObserver and call dart.getViewTreeObserver().removeOnPreDrawListener(this); in your onPreDraw() method
ViewTreeObserver vto = iv.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
dart.getViewTreeObserver().removeOnPreDrawListener(this);
finalHeight = dart.getMeasuredHeight();
finalWidth = dart.getMeasuredWidth();
Toast.makeText(MainActivity.this," "+finalHeight,Toast.LENGTH_SHORT).show();
return true;
}
});
Here is my Code to return Height of view:
int height = 0;
public int getViewHeight(final View v) {
v.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
v.getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
} else {
v.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
}
height = v.getMeasuredHeight();
//
Log.v(" height", v.getMeasuredHeight() + "");
}
});
Log.v(" return height", v.getMeasuredHeight() + "");
return height;
}
First It return 0. then the height value changes.
Can anyone let me know how to return height of view when it measured in onGlobalLayout. Return statement not working in overrided method.
OR
Is there any other way to make a static method which return height of view by passing View instance.
***try this way*
i get View Height and Width as per View**
public class Test extends Activity {
private RelativeLayout layout;
private int temp;
ViewTreeObserver vto;
SharedPreferences sharedPreferences;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
sharedPreferences = getSharedPreferences("savePref",
Context.MODE_PRIVATE);
layout = (RelativeLayout) findViewById(R.id.layout);
temp = set(layout);
Log.e("temp", "" + sharedPreferences.getInt("key", 0));
}
private int set(final RelativeLayout layout) {
vto = layout.getViewTreeObserver();
final Editor editor = sharedPreferences.edit();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#SuppressWarnings("deprecation")
#Override
public void onGlobalLayout() {
layout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
temp = layout.getMeasuredHeight();
editor.putInt("key", temp);
editor.commit();
}
});
if (sharedPreferences.contains("key")) {
Log.e("contains", "" + sharedPreferences.getInt("key", 0));
}
return sharedPreferences.getInt("key", 0);
}}
I have a TextView with maximun 3 lines and a "Show more" button below it. The logic is that if the text in the TextView can fit inside it, the "Show more" button is hidden; otherwise if the text cannot fit in 3 lines, the "Show more" is shown.
My way (which is not working) is that: detect if the TextView is ellipsized by using textView.getLayout().getEllipsisCount(maxNumberOfline) then hide or show the "Show more" button. But the call textView.getLayout() return null when the layout is not finish yet. I tried to put textView.getLayout().getEllipsisCount(maxNumberOfline) in onStart() and onResume() but no luck.
Does anyone have another way to do this?
Try this way,hope this will help you to solve your problem.
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textview = (TextView) findViewById(R.id.textview);
textview.setText("demotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotextdemotext");
TextViewResizable(textview,3,"See More");
}
public void TextViewResizable(final TextView tv,final int maxLine, final String expandText) {
if (tv.getTag() == null) {
tv.setTag(tv.getText());
}
ViewTreeObserver vto = tv.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#SuppressWarnings("deprecation")
#Override
public void onGlobalLayout() {
ViewTreeObserver obs = tv.getViewTreeObserver();
obs.removeGlobalOnLayoutListener(this);
if (maxLine <= 0) {
int lineEndIndex = tv.getLayout().getLineEnd(0);
String text = tv.getText().subSequence(0,lineEndIndex - expandText.length() + 1)+ " " + expandText;
tv.setText(text);
tv.setMovementMethod(LinkMovementMethod.getInstance());
tv.setText(addClickablePartTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText), TextView.BufferType.SPANNABLE);
} else if (tv.getLineCount() >= maxLine) {
int lineEndIndex = tv.getLayout().getLineEnd(maxLine - 1);
String text = tv.getText().subSequence(0,lineEndIndex - expandText.length() + 1)+ " " + expandText;
tv.setText(text);
tv.setMovementMethod(LinkMovementMethod.getInstance());
tv.setText(addClickablePartTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText), TextView.BufferType.SPANNABLE);
}
}
});
}
private SpannableStringBuilder addClickablePartTextViewResizable(final Spanned strSpanned, final TextView tv,final String expandText) {
String str = strSpanned.toString();
SpannableStringBuilder ssb = new SpannableStringBuilder(strSpanned);
if (str.contains(expandText)) {
ssb.setSpan(new Spannable(Color.BLUE, true) {
#Override
public void onClick(View widget) {
tv.setLayoutParams(tv.getLayoutParams());
tv.setText(tv.getTag().toString(),TextView.BufferType.SPANNABLE);
tv.invalidate();
}
}, str.indexOf(expandText), str.indexOf(expandText)+ expandText.length(), 0);
}
return ssb;
}
class Spannable extends ClickableSpan {
private int color = -1;
private float fontSize = -1;
private boolean isUnderline = true;
/**
* Constructor
*/
public Spannable() {
}
/**
* Constructor
*/
public Spannable(int color) {
this.color = color;
}
/**
* Constructor
*/
public Spannable(float fontSize) {
this.fontSize = fontSize;
}
/**
* Constructor
*/
public Spannable(boolean isUnderline) {
this.isUnderline = isUnderline;
}
/**
* Constructor
*/
public Spannable(int color, boolean isUnderline) {
this.isUnderline = isUnderline;
this.color = color;
}
/**
* Constructor
*/
public Spannable(int color, float fontSize) {
this.color = color;
this.fontSize = fontSize;
}
/**
* Overrides methods
*/
#Override
public void updateDrawState(TextPaint ds) {
if (color != -1) {
ds.setColor(color);
}
if (fontSize > 0) {
ds.setTextSize(fontSize);
}
ds.setUnderlineText(isUnderline);
}
#Override
public void onClick(View widget) {
}
}
I also had this kind of problem, the following code actually fixed it:
mTextView.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
showHideMoreButton(mTextView);
}
});
public void showHideMoreButton(TextView mTextView) {
Layout layout = mTextView.getLayout();
if (layout != null) {
int lines = layout.getLineCount();
if (lines > 0) {
int ellipsisCount = layout.getEllipsisCount(lines - 1);
if (ellipsisCount > 0) {
mShowMoreButton.setVisibility(View.VISIBLE);
}
}
}
}
until I noticed that it's not working in OS version 2.3.5. Even though the mTextView.getLineCount() is returning the correct number of lines, the layout.getEllipsisCount(lines - 1) never returns number which is greater than 0. What happened next is that the "Show More" button never appears although the TextView has already been truncated at the end. Then I realized that the implementation can be changed to the following. It's working now.
public void showHideMoreButton(TextView mTextView) {
int lines = mTextView.getLineCount();
if (lines > 2) {
mShowMoreButton.setVisibility(View.VISIBLE);
mTextView.setSingleLine(false);
mTextView.setEllipsize(TextUtils.TruncateAt.END);
mTextView.setLines(2); //no. of lines you want your textview to display
}
}