0

I need to show some view when my mTxtText has maxLinesCount or more lines. I checked these questions: first and second

What I have as a result in my getView method:

mTxtText.setText(Html.fromHtml(output));
mTxtText.getViewTreeObserver().addOnGlobalLayoutListener(
        new OnGlobalLayoutListener() {

            @SuppressWarnings("deprecation")
            @Override
            public void onGlobalLayout() {

                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                    mTxtText.getViewTreeObserver()
                            .removeGlobalOnLayoutListener(this);
                } else {
                    mTxtText.getViewTreeObserver()
                            .removeOnGlobalLayoutListener(this);
                }

                if (isCollapseOn
                        && mTxtText.getLineCount() >= maxLinesCount) {
                    mTxtExpand.setVisibility(View.VISIBLE);
                } else {
                    mTxtExpand.setVisibility(View.GONE);
                }
            }
        });

But I have got very interesting results: this listener is called only for some items in my adapter and for other items the visibility of mTxtExpand is set randomly. When I scroll my list even items for which the listener was called show wrong views.

Thanks for any help.

Community
  • 1
  • 1
Alex Zaitsev
  • 2,013
  • 4
  • 30
  • 56
  • 1
    the `getView()` method is magic. It will reuse, recycle and redraw views constantly, so it's not a reliable method to use with a `Listener` or an `Observer`. – tolgap Aug 02 '13 at 14:15
  • @tolgap where should I place the listener? – Alex Zaitsev Aug 03 '13 at 08:09
  • You should avoid using a `ListAdapter` in it's entirety. Use a `ScrollView` and inflate each element into it as a `LinearLayout`. Trust me, I tried animating ListView elements too, but animations kept recurring randomly as I kept scrolling. A `ScrollView's` `onScoll()` method works like you would expect it to work. – tolgap Aug 03 '13 at 09:49
  • Unfortunately I can't use this approach, because I use pull-to-refresh and load-more patterns.. So I think there is no solution for me. Anyway, thank you. – Alex Zaitsev Aug 03 '13 at 13:14
  • +1 to tolgap about `getView()`. It is possible to have all sorts of things going on in a listview, by implementing custom views, as long as all the logic is contained within the view. You would then expose simple setters to be called from `getView` and a reset method that is always called from `getView` to ensure nothing crazy happens. Works quite well, although you do loose the ability to do things like ViewHolder. Have you tried this at all? – Tom Aug 05 '13 at 15:45
  • Why do you need the listener in the first place? Why not just put your if getLineCount() right after mTxtText.setText? – talkol Aug 06 '13 at 02:42
  • @talkol because `getLineCount()` returns 0 directly in `getView()` – Alex Zaitsev Aug 06 '13 at 10:04

1 Answers1

0

I suggest you make the following changes:

  1. I've never used view tree observer, but it seems to me that a single view tree observer for your entire list is enough. I don't think you need a separate observer for each text view.

  2. Since you want to keep getting layout notifications, don't remove your single view tree observer after one notification. Remove it when you destroy your entire list.

  3. On each layout notification, go over all of your list cells and check the number of lines in each one. You can go over them by getting all of the list's children (using getChildAt() - not using your adapter!). You don't need to worry about concurrency issues because there's a single UI thread, so getView will not run in the middle of your iteration.

  4. Each of your list cells contains a text view and a txt expand. Give them specific id's so you could search for them easily given a cell view (their parent).

  5. In your big iteration (on layout notification), after you check each text view, you can get its corresponding txt expand by going to the parent of the text view and searching for it using the id.

  6. In your observer handler, don't rely on external state variables except maybe getting a reference for the entire list.

talkol
  • 12,564
  • 11
  • 54
  • 64