studio - todo sobre android pdf




¿Cómo permitir que EditText ocupe todo el espacio que necesita para poder desplazarse junto con el contenido que se encuentra arriba? (3)

Fondo

Tengo un diseño que tiene algunas vistas en la parte superior, que debe ser desplazable junto con un texto de edición debajo de ellos.

El EditText toma el resto del espacio, tanto espacio como necesita.

Aquí hay un ejemplo de diseño de POC que lo demuestra (usamos solo 2 EditTexts aquí):

<android.support.v4.widget.NestedScrollView android:id="@+id/nestedScrollView"
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="match_parent" android:fillViewport="true">

    <LinearLayout
        android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical">

        <EditText
            android:id="@+id/titleEditText" android:layout_width="match_parent" android:layout_height="wrap_content"
            android:ellipsize="end" android:hint="title" android:imeOptions="actionNext|flagNoExtractUi"
            android:inputType="text|textAutoCorrect|textCapSentences" android:maxLines="1"
            android:nextFocusDown="@id/contentEditText" android:nextFocusForward="@id/contentEditText"
            android:scrollHorizontally="true" android:textColor="#2a2f3b" android:textColorHint="#a3a3a3"
            android:textSize="21sp"/>

        <EditText
            android:id="@+id/contentEditText" android:layout_width="match_parent" android:layout_height="match_parent"
            android:gravity="top" android:hint="content" android:background="@android:drawable/alert_light_frame"
            android:imeOptions="actionDone|flagNoEnterAction|flagNoExtractUi" android:textSize="18sp"
            android:inputType="textMultiLine|textAutoCorrect|textCapSentences"/>

    </LinearLayout>

</android.support.v4.widget.NestedScrollView>

He establecido un marco de fondo para tener una indicación visual de qué tan grande es el EditText.

El problema

He encontrado tantas soluciones a lo que escribí, pero ninguna de ellas maneja bien el desplazamiento.

Lo que siempre estoy viendo, es al menos uno de esos problemas:

  1. No se puede desplazar la página completa (solo EditText puede ser desplazable, lo que estoy tratando de evitar), por lo que ya no puedo acceder a las vistas en la parte superior.
  2. Cuando ingreso texto, el cursor puede salir del área visible
  3. A medida que escribo más y más líneas, no se desplaza por toda la página. Solo en el EditText mismo.

Lo que he intentado

He intentado esas soluciones:

  1. Todo desde here , here , here , here . Tal vez más, pero no hice suficiente seguimiento ...
  2. Intenté varios valores windowSoftInputMode en el manifiesto, y traté de establecer isNestedScrollingEnabled en el NestedScrollView.
  3. Probé varias configuraciones en el XML, para permitir que EditText ocupe todo el espacio que necesita, para evitar que se pueda desplazar dentro de él.

La pregunta

¿Cómo puedo hacer que el EditText inferior ocupe todo el espacio que necesita y pueda seguir desplazando NestedScrollView completo sin problemas en la edición?

EDITAR: ya que la aplicación original es un poco más compleja, con algunas vistas en la parte inferior (dentro de lo que es una barra de herramientas) que se ocultan automáticamente cuando no está enfocado en el texto de edición inferior, esto hizo que la respuesta no la encontré trabajar.

Además, accidentalmente he otorgado la recompensa a la respuesta incorrecta, así que aquí hay una nueva recompensa, en el POC más complejo. La pregunta sigue siendo la misma. El NestedScrollView debe permanecer en el mismo lugar, sin desplazarse cuando se enfoca en el texto de edición inferior.

<LinearLayout
    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" android:orientation="vertical">

    <View
        android:layout_width="0dp" android:layout_height="0dp" android:focusable="true"
        android:focusableInTouchMode="true"/>

    <android.support.v4.widget.NestedScrollView
        android:id="@+id/nestedScrollView" android:layout_width="match_parent" android:layout_height="0px"
        android:layout_weight="1" android:fillViewport="true">

        <LinearLayout
            android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical">

            <EditText
                android:id="@+id/titleEditText" android:layout_width="match_parent" android:layout_height="wrap_content"
                android:ellipsize="end" android:hint="title" android:imeOptions="actionNext|flagNoExtractUi"
                android:inputType="text|textAutoCorrect|textCapSentences" android:maxLines="1"
                android:nextFocusDown="@id/contentEditText" android:nextFocusForward="@id/contentEditText"
                android:scrollHorizontally="true" android:textColor="#2a2f3b" android:textColorHint="#a3a3a3"
                android:textSize="21sp"/>

            <android.support.constraint.ConstraintLayout
                android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent"
                android:background="@android:drawable/alert_light_frame" android:clickable="true"
                android:focusable="false">

                <EditText
                    android:id="@+id/contentEditText" android:layout_width="match_parent"
                    android:layout_height="wrap_content" android:background="@null" android:gravity="top"
                    android:hint="content" android:imeOptions="actionDone|flagNoEnterAction|flagNoExtractUi"
                    android:inputType="textMultiLine|textAutoCorrect|textCapSentences" android:textSize="18sp"/>
            </android.support.constraint.ConstraintLayout>

        </LinearLayout>

    </android.support.v4.widget.NestedScrollView>

    <LinearLayout
        android:layout_width="match_parent" android:layout_height="wrap_content" android:animateLayoutChanges="true"
        android:orientation="vertical">

        <LinearLayout
            android:id="@+id/autoHideLayout" android:layout_width="match_parent" android:layout_height="wrap_content"
            android:orientation="horizontal" android:visibility="gone" tools:visibility="visible">

            <Button
                android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="button"/>

            <Button
                android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="button2"/>

        </LinearLayout>
    </LinearLayout>
</LinearLayout>


class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        container.setOnClickListener {
            contentEditText.requestFocus()
            contentEditText.setSelection(contentEditText.length())
        }
        contentEditText.setOnFocusChangeListener { view, hasFocus ->
            autoHideLayout.visibility = if (hasFocus) View.VISIBLE else View.GONE
            if (hasFocus)
                nestedScrollView.scrollTo(0, 0)
        }
    }
}

Debería poder lograr lo que desea calculando los minLines según la altura de la pantalla. Vea el ejemplo de actividad y diseño a continuación.

Necesitará escribir un poco de texto para usar las líneas mínimas y crecer más allá de la altura de la pantalla para iniciar el comportamiento de desplazamiento, pero puede minLines agregando algunas líneas constantes al cálculo de minLines

public class ScrollingActivity extends AppCompatActivity
{
    EditText editText2;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scrolling);

        editText2 = findViewById(R.id.editText2);

        int minHeight = getResources().getDisplayMetrics().heightPixels - editText2.getTop();
        float lineHeight = editText2.getPaint().getFontMetrics().bottom - editText2.getPaint().getFontMetrics().top;
        int minLines = (int)(minHeight/lineHeight);
        editText2.setMinLines(minLines);
    }
}

Aquí está el diseño

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    android:id="@+id/parentLayout"
    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"
    tools:context="com.my.package.ScrollingActivity">
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#000000">
        <android.support.constraint.ConstraintLayout
            android:id="@+id/scrollingLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <EditText
                android:id="@+id/editText1"
                android:layout_margin="15dp"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:layout_constraintTop_toTopOf="parent"
                android:background="#FFFFFF"/>
            <EditText
                android:id="@+id/editText2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:layout_constraintTop_toBottomOf="@id/editText1"
                app:layout_constraintBottom_toBottomOf="parent"
                android:layout_margin="15dp"
                android:background="#FFFFFF"/>
        </android.support.constraint.ConstraintLayout>
    </ScrollView>
</android.support.constraint.ConstraintLayout>

EDITAR

Reconstruí su solución y puede corregir el problema de enfoque configurando este oyente en su EditText. Funciona al anular la acción de desplazamiento cuando el Texto de edición recibe el foco, para solo desplazarse lo suficiente como para que el cursor sea visible.

contentEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View view, boolean hasFocus) {
        if(hasFocus){
            nestedScrollView.scrollTo(0, 0);
        }
    }
});

Editar 2

He actualizado mi respuesta para reflejar los cambios con la nueva recompensa, esto debería ser bastante parecido a lo que necesita, si he entendido la pregunta correctamente.

public class ScrollingActivity extends AppCompatActivity
{
    ConstraintLayout parentLayout;
    EditText contentEditText;
    NestedScrollView nestedScrollView;
    LinearLayout autoHideLayout;

    boolean preventScroll = true;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scrolling);

        contentEditText = findViewById(R.id.contentEditText);
        nestedScrollView = findViewById(R.id.nestedScrollView);
        autoHideLayout = findViewById(R.id.autoHideLayout);
        parentLayout = findViewById(R.id.parentLayout);
        nestedScrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);

        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);


        parentLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int minHeight = autoHideLayout.getTop() - contentEditText.getTop();
                float lineHeight = contentEditText.getPaint().getFontMetrics().bottom - contentEditText.getPaint().getFontMetrics().top;
                int minLines = (int)(minHeight/lineHeight);
                if(minLines != contentEditText.getMinLines()){
                    contentEditText.setMinLines(minLines);
                }
            }
        });


        contentEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View view, boolean hasFocus) {
                ViewGroup.LayoutParams layoutParams = autoHideLayout.getLayoutParams();
                if(hasFocus){
                    nestedScrollView.scrollTo(0,0);
                    layoutParams.height = ConstraintLayout.LayoutParams.WRAP_CONTENT;
                } else{
                    layoutParams.height = 0;
                }
                autoHideLayout.setLayoutParams(layoutParams);
            }
        });
    }
}

Aquí está el nuevo diseño

    <android.support.constraint.ConstraintLayout
    android:id="@+id/parentLayout"
    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" android:orientation="vertical"
    android:animateLayoutChanges="true">

    <android.support.v4.widget.NestedScrollView
        android:id="@+id/nestedScrollView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:focusable="false"
        android:focusableInTouchMode="false"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/autoHideLayout"
        >

        <LinearLayout
            android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">

            <EditText
                android:id="@+id/titleEditText" android:layout_width="match_parent" android:layout_height="wrap_content"
                android:ellipsize="end" android:hint="title" android:imeOptions="actionNext|flagNoExtractUi"
                android:inputType="text|textAutoCorrect|textCapSentences" android:maxLines="1"
                android:nextFocusDown="@id/contentEditText" android:nextFocusForward="@id/contentEditText"
                android:scrollHorizontally="true" android:textColor="#2a2f3b" android:textColorHint="#a3a3a3"
                android:background="@android:drawable/alert_light_frame"
                android:textSize="21sp"/>

            <EditText
                android:id="@+id/contentEditText" android:layout_width="match_parent"
                android:layout_height="wrap_content" android:background="@android:drawable/alert_light_frame" android:gravity="top"
                android:hint="content" android:imeOptions="actionDone|flagNoEnterAction|flagNoExtractUi"
                android:inputType="textMultiLine|textAutoCorrect|textCapSentences" android:textSize="18sp"/>

        </LinearLayout>

    </android.support.v4.widget.NestedScrollView>

    <LinearLayout
        android:id="@+id/autoHideLayout" android:layout_width="0dp" android:layout_height="0dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:orientation="horizontal" android:visibility="visible" tools:visibility="visible"
        app:layout_constraintBottom_toBottomOf="parent">

        <Button
            android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="button"/>

        <Button
            android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="button2"/>

    </LinearLayout>
</android.support.constraint.ConstraintLayout>

Me doy cuenta de que NestedScrollView no se desplazará hasta que su contenido salga de la pantalla. Hago un truco y coloco algunas filas vacías después del texto ingresado para garantizar que el contenido salga de la pantalla actual. Después de que el foco de las pérdidas de EditText quito las filas vacías.

public class MainActivity extends AppCompatActivity {
        String EMPTY_SPACES = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
        EditText mEditText;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            mEditText = findViewById(R.id.contentEditText);

            mEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
                @Override
                public void onFocusChange(View view, boolean hasFocus) {
                    if (!hasFocus) {
                        // code to execute when EditText loses focus
                        mEditText.setText(mEditText.getText().toString().trim());
                    }
                }
            });

            mEditText.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

                }

                @Override
                public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                    int charsThatGuaranteesTextIsOutOfScreen = 400;
                    if (mEditText.hasFocus() && charSequence.length() < charsThatGuaranteesTextIsOutOfScreen) {
                        mEditText.setText(String.format(Locale.getDefault(), "%1$s%2$s", charSequence, EMPTY_SPACES));
                        mEditText.setSelection(i2);
                    }
                }

                @Override
                public void afterTextChanged(Editable editable) {

                }
            });
        }

        @Override
        public void onBackPressed() {
            if (mEditText.hasFocus()) {
                mEditText.clearFocus();
            } else {
                super.onBackPressed();
            }
        }
    }

Tengo algunas soluciones para esto, envolviendo el EditText inferior con un diseño que le otorgará enfoque.

No requiere mucho código

activity_main.xml

<android.support.v4.widget.NestedScrollView
    android:id="@+id/nestedScrollView" xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true">

    <LinearLayout
        android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical">

        <EditText
            android:id="@+id/titleEditText" android:layout_width="match_parent" android:layout_height="wrap_content"
            android:ellipsize="end" android:hint="title" android:imeOptions="actionNext|flagNoExtractUi"
            android:inputType="text|textAutoCorrect|textCapSentences" android:maxLines="1"
            android:nextFocusDown="@id/contentEditText" android:nextFocusForward="@id/contentEditText"
            android:scrollHorizontally="true" android:textColor="#2a2f3b" android:textColorHint="#a3a3a3"
            android:textSize="21sp"/>

        <android.support.constraint.ConstraintLayout
            android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent"
            android:background="@android:drawable/alert_light_frame" android:clickable="true" android:focusable="false">

            <EditText
                android:id="@+id/contentEditText" android:layout_width="match_parent"
                android:layout_height="wrap_content" android:background="@null" android:gravity="top"
                android:hint="content" android:imeOptions="actionDone|flagNoEnterAction|flagNoExtractUi"
                android:inputType="textMultiLine|textAutoCorrect|textCapSentences" android:textSize="18sp"/>
        </android.support.constraint.ConstraintLayout>

    </LinearLayout>

</android.support.v4.widget.NestedScrollView>

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        container.setOnClickListener {
            contentEditText.requestFocus()
            contentEditText.setSelection(contentEditText.length())
        }
        contentEditText.setOnFocusChangeListener { view, hasFocus ->
            if (hasFocus) {
                nestedScrollView.scrollTo(0, 0)
            }
        }
    }
}

manifiesto

<manifest package="com.example.user.myapplication" xmlns:android="http://schemas.android.com/apk/res/android">

    <application
        android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme">
        <activity android:name=".MainActivity" android:windowSoftInputMode="adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>






android-nestedscrollview