studio sobre programacion para herramientas desarrollo con avanzado aplicaciones android android-edittext android-nestedscrollview

android - sobre - ¿Cómo permitir que EditText ocupe todo el espacio que necesita para poder desplazarse junto con el contenido que se encuentra arriba?



manual de programacion android (4)

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>

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) } } }


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(); } } }


Su resultado esperado se puede lograr cambiando el layout.xml y MainActivity. Cambie layout_height y agregando layout_weight para ConstraintLayout siguiente manera:

<?xml version="1.0" encoding="utf-8"?> <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="0dp" android:layout_weight="1" android:background="@android:drawable/alert_light_frame" android:clickable="true" android:focusable="false" android:nestedScrollingEnabled="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="visible" 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>

Manifest.xml es:

<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.DEFAULT" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>

Registre el valor actual de scrollX y scroll Y para NestedScrollView y ajuste NestedScrollView siguiente manera:

MainActivity.java

public class MainActivity extends AppCompatActivity { private int scrollX; private int scrollY; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final EditText editText = findViewById(R.id.contentEditText); final LinearLayout autoHideLayout = findViewById(R.id.autoHideLayout); ConstraintLayout container = findViewById(R.id.container); container.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { autoHideLayout.setVisibility(View.VISIBLE); editText.requestFocus(); editText.setSelection(editText.length()); } }); final NestedScrollView nestedScrollView = findViewById(R.id.nestedScrollView); editText.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { scrollX = nestedScrollView.getScrollX(); scrollY = nestedScrollView.getScrollY(); autoHideLayout.setVisibility(View.VISIBLE); return false; } }); editText.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) nestedScrollView.scrollTo(scrollX, scrollY); if (!hasFocus) { autoHideLayout.setVisibility(View.GONE); } } }); } }

No se desplazó cuando no era necesario. Vea la captura de pantalla:


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>