28

I can't get my elements, for example ListView, to resize properly.

I got a ListActivity for searching, with a dashboard, an editbox and a listview. The idea is to hide the actionbar while the keyboard is showing.

I extended LinearLayout, to listen to view size changes (as recommended here) :

public class SizeChangingLinearLayout extends LinearLayout {
    //...
    @Override
    protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld)
    {        
        View actionbar = mainView.findViewById(R.id.actionbar);

        if (yNew > yOld) 
            actionbar.setVisibility(View.VISIBLE);
        else if (yNew < yOld) 
            actionbar.setVisibility(View.GONE);

        super.onSizeChanged(xNew, yNew, xOld, yOld);

    }
}

The hiding/showing of the actionbar works as expected but there is a gap below the ListView of the same height as the hidden actionbar. As soon as any graphics change (e.g. writing in the editbox) the ListView fills the gap. A similar behavior appears in reverse, when hiding the keyboard.

enter image description here

[Edit]

The same problem also appears in changing other layout. Changing Visibility of things in onSizeChanged shows directly, but changing sizes and margins does not show until some other user action redraws those views. Invalidation does not work from onSizeChanged.

[/Edit]

I have tried to refresh the graphics by:

  • invalidate-ing both the custom LinearLayout and the ListView (as recommended here)
  • notifyDataSetChanged on the list's adapter
  • forceLayout

... and more, without success. Why is the ListView not resizing at first? Do I have to override onLayout in my extended LinearLayout? What have I missed?

Community
  • 1
  • 1
JOG
  • 5,590
  • 7
  • 34
  • 54
  • Not any update works, I noticed. "As soon as any graphics change", I wrote. But for example a popup won't make the changes made show. I guess the right elements has to be invalidated, but they don't. – JOG Jun 21 '11 at 06:37
  • The problem also appears for all layout changes, for example changing margins of the EditText. But _adding_ layout elements, for example a button to the right of the box, shows immediately though. – JOG Jun 21 '11 at 06:51

4 Answers4

39

Adding the following at the end of onSizeChanged() will solve it:

Handler handler = new Handler();
handler.post(new Runnable() {

    @Override
    public void run() {
        requestLayout();
    }
});

See the answer to this question: Views inside a custom ViewGroup not rendering after a size change

Community
  • 1
  • 1
aspartame
  • 4,622
  • 7
  • 36
  • 39
  • 14
    View has a post() method, so you don't need to allocate the Handler. – ThomasW Nov 08 '11 at 01:21
  • 1
    I was changing the size of child views in `onSizeChanged`, so I had to put the resizing of said child views in the runnable before calling `requestLayout()` – James Coote Jan 18 '12 at 13:48
0

This could be a long shot...

Have you tried playing with the android:layout_height="" setting for the ListView?

Maybe using match_parent or wrap_content could force it to work...

As I said... a long shot!

neildeadman
  • 3,974
  • 13
  • 42
  • 55
  • Just like @PravinCG's suggestion, it does not work. Apparently no layout changes made in `onSizeChanged` on any View is applied until another layout update is made. – JOG Jun 20 '11 at 15:59
0

You can force the ListView to redraw by changing its height by 1px and calling

requestLayout()

PravinCG
  • 7,688
  • 3
  • 30
  • 55
  • Tried it, and it does not work, unfortunately: `setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, (int) getResources().getDimension(R.dimen.another_value)));` `requestLayout();` It gets the new height only after any other layout changes. Just like in the screenshots of mine. The same behaviour also appears on all Views I try to manipulate in the `onSizeChanged` method. – JOG Jun 20 '11 at 15:17
0

It's possible to do what you want by registering a setOnFocusChangeListener and a setOnClickListener to the EditText.

There are a lot of different scenarios to consider when it comes to navigation and things might need to be changed to work with a certain layout.

Anyway, start by overriding onSizeChanged to show the hidden element when the back button is touched.

public class MyLinearLayout extends LinearLayout {

    private MyListActivity mMyListActivity;

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

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

    public void setMyListActivity(MyListActivity mla) {
        mMyListActivity = mla;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        // show the element when we get more room       
        if (h > oldh) {
            if (mMyListActivity != null) {
                mMyListActivity.showBar();
            }
        }
        super.onSizeChanged(w, h, oldw, oldh);
    }
}

In the ListActivity we grab the MyLinearLayout and pass this to it. Then a setOnFocusChangeListener is registered to handle things when the EditText's focus changes. The setOnClickListener is used to hide the element when the EditText already has focus.

public class MyListActivity extends ListActivity {

    private ArrayList<MyData> mDataList = new ArrayList<MyData>();

    private MyLinearLayout mMyLinearLayout; 
    private LinearLayout mHideMeLinearLayout;
    private EditText mEditText;

    public void showBar() {
        if (mHideMeLinearLayout != null) {
            mHideMeLinearLayout.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Get MyLinearLayout and pass this to it.
        mMyLinearLayout = (MyLinearLayout) findViewById(R.id.myLinearLayout);
        mMyLinearLayout.setMyListActivity(this);

        // the LinearLayout to be hidden
        mHideMeLinearLayout = (LinearLayout) findViewById(R.id.LinearLayoutToHide);

        mEditText = (EditText) findViewById(R.id.editText);     
        mEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                InputMethodManager imm = (InputMethodManager) getSystemService(Service.INPUT_METHOD_SERVICE);
                if (hasFocus) {
                    imm.showSoftInput(mEditText, 0);
                    mHideMeLinearLayout.setVisibility(View.GONE);
                } else {
                    imm.hideSoftInputFromWindow(mMyLinearLayout.getWindowToken(), 0);
                    mHideMeLinearLayout.setVisibility(View.VISIBLE);
                }
            }
        });
        mEditText.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mHideMeLinearLayout.setVisibility(View.GONE);
            }
        });

        .....
    }

    .....
}

I'll provide a working example later, but gotta run now.

rochdev
  • 3,835
  • 2
  • 21
  • 18