简体   繁体   中英

How to make invisible a partially visible view inside LinearLayout?

Let assume we have a simple LinearLayout with vertical orientation with size width: 100dp and height: 100dp

Inside the layout there are 10 TextViews (width: fill_parent, height: wrap_content, max_lines = 1, scroll_horizontally = true, ellipsize = end). Each text view is visible, and filled with 14dp text "What a text". Final density of the android device does not matter. Most of TextViews will be displayed correctly, but due to enforced layout size, some of them will be invisible or clipped.

The goal is: detect clipped views, and hide them.

I've tried to use custom LinearLayout subclass, where during layout phase each child view was measured and compared with destination size. The problem is that measure call, changes internal view measurement values - if child is not a simple view but a ViewGroup - it is not displayed correcly. As far as I know - after measure phase - there should be layout phase. But everything takes place inside layout phase of the custom LinearLayout already.

EDIT:

OK, simplifying my question - I want to have a LinearLayout or generally speaking - a ViewGroup, which will not draw partially visible children.

Code of custom layout class:

public final class ClipAwareLinearLayout extends LinearLayout
{    
    public ClipAwareLinearLayout(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public ClipAwareLinearLayout(Context context)
    {
        super(context);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b)
    {
        super.onLayout(changed, l, t, r, b);
        final int width = r - l;
        final int height = b - t;
        final int count = getChildCount();
        final int msWidth = MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST);
        final int msHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
        View child;
        int measuredHeight;
        int childHeight;
        for (int i = 0; i < count; ++i)
        {
            child = getChildAt(i);
            if (child != null)
            {
                childHeight = child.getHeight();
                child.measure(msWidth, msHeight);
                measuredHeight = child.getMeasuredHeight();
                final boolean clipped = (childHeight < measuredHeight);
                child.setVisibility(clipped ? View.INVISIBLE : View.VISIBLE);
            }
        }
    }

}`

Try the code below. It should work but I haven't tested so I may be wrong:

class ClippedLinear extends LinearLayout {

    public ClippedLinear(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        boolean status = false;
        for (int i = getChildCount() - 1; i > 0; i--) {
            if (status) {
                continue;
            }
            final View child = getChildAt(i);
            final int childHeight = child.getMeasuredHeight();
            if (childHeight == 0) {
                child.setVisibility(View.GONE);         
            } else {                
                child.measure(widthMeasureSpec, heightMeasureSpec);
                if (childHeight < child.getMeasuredHeight()) {                  
                    child.setVisibility(View.GONE);
                }
                status = true;
            }
        }
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM