Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Some layouts don't draw when the keyboard goes down

I'm working an app that draws objects on SurfaceView under some parameters, defined by the user. I created the layout for the app, which involves an header, footer, input (where user enters parameters to draw) and a custom SurfaceView.

Here's the layout that simplified:

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- Custom SurfaceView Layout -->

    <org.firengine.myapp.CustomPreview
        android:id="@+id/container_content"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <!-- Header Layout: This is basically a Toolbar, with having a top padding of status bar height (see Note). -->

    <FrameLayout
        android:id="@+id/container_header"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="@color/colorTint"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">...</FrameLayout>

    <!-- Footer Layout - This is just a container, with having a bottom padding of navigation bar height (see Note). -->

    <FrameLayout
        android:id="@+id/container_footer"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="@color/colorTint"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">...</FrameLayout>

    <!-- Input Layout - This is a empty container that shows views dynamically. -->

    <LinearLayout
        android:id="@+id/container_input"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:gravity="bottom|center_horizontal"
        android:orientation="vertical"
        app:layout_constraintBottom_toTopOf="@+id/container_footer"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/container_header" />

</android.support.constraint.ConstraintLayout>

The input layout generate dynamic views, based on parameters.

Suppose I create a EditText inside input layout, so that the keyboard appears if you interact with that.

This is before the keyboard shows up.

Before Keyboard Shows Up.

This is when the keyboard is showing. Notice that the app layout is panned and the header layout got invisible.

Keyboard Is Showing.

The problem occurs when the keyboard goes down. The header layout, which is invisible earlier, stays invisible all the time (until the user interacts with the app).

After Keyboard Shows Up.

I turned on GPU overdraw to check the problem (also setting SurfaceView background color to white), and here is the result.

Before:

Before with GPU overdraw.

After:

After with GPU overdraw.

Also, here's my custom SurfaceView class (I think that the custom SurfaceView is blocking the UI thread to draw the layouts that disappeared).

public class CustomPreview extends SurfaceView implements SurfaceHolder.Callback {

    private final Handler handler = new Handler();
    private final Runnable runnable = new Runnable() {
        @Override
        public void run() {
            draw();
        }
    };

    private Renderer renderer;

    private boolean visible;
    private boolean canLoadData;

    private HashMap<String, String> data;

    public CustomPreview(Context context, AttributeSet attrs) {
        super(context, attrs);
        getHolder().addCallback(this);
        getHolder().setFormat(PixelFormat.RGBA_8888);
        visible = false;
        canLoadData = false;
        renderer= new Renderer(context);
        data = new HashMap<>();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        visible = true;
        refreshHandler(0);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        renderer.updateDimensions(width, height);
        canLoadData = true;
        renderer.updateData(data);
        refreshHandler(0);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        renderer.clearData();
        visible = false;
        canLoadData = false;
        refreshHandler(0);
    }

    public void setVisibility(boolean visible) {
        this.visible = visible;
        refreshHandler(0);
    }

    private void draw() {
        Canvas canvas = null;
        try {
            canvas = getHolder().lockCanvas();
            if (canvas != null) {
                renderer.draw(canvas);
            }
        } finally {
            if (canvas != null) {
                getHolder().unlockCanvasAndPost(canvas);
            }
        }
        refreshHandler(60000);
    }

    public void saveData(String key, String value) {
        data.put(key, value);
        if (canLoadData) {
            renderer.updateData(data);
        }
        refreshHandler(0);
    }

    private void refreshHandler(long delay) {
        handler.removeCallbacks(runnable);
        if (visible) {
            if (delay > 0) {
                handler.postDelayed(runnable, delay);
            } else {
                handler.post(runnable);
            }
        }
    }

    public String loadData(String key) {
        return data.get(key);
    }

Am I doing something wrong? If so, can someone explain what it is?

I'm glad if someone helps me out. Thank you.

Note: Heres some extra information about the layout.

  1. Footer layout was originally had a AdView, which is not included in the layout.
  2. SYSTEM_UI_FLAG_HIDE_NAVIGATION and SYSTEM_UI_FLAG_FULLSCREEN flags was added to the activity and because of that, paddings were set in respective layouts to avoid overlapping.
  3. And, header layout has 2 Toolbar views, which one of them are seen in the images above.
like image 431
JudgedPluto Avatar asked Jan 30 '18 11:01

JudgedPluto


1 Answers

Try following in the Manifest

android:windowSoftInputMode="adjustNothing"

<activity 
    android:name=".app.main.MainActivity"
    android:windowSoftInputMode="adjustNothing">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>
like image 98
Nasimxon Avatar answered Oct 28 '22 00:10

Nasimxon