I have a layout that has some views at the top, which should be scrollable together with an EditText below them.
The EditText takes the rest of the space, as much space as it needs.
Here's a sample POC layout that demonstrate it (used just 2 EditTexts here) :
<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>
I've set a background frame to have a visual indication of how large the EditText is.
I've found so many solutions to what I wrote, but none of them actually handles the scrolling well.
What I'm always seeing, is at least one of those issues:
I've tried those solutions:
windowSoftInputMode
values in the manifest, and tried to set isNestedScrollingEnabled
in the NestedScrollView. How can I make the bottom EditText to take as much space as it needs, and still be able to scroll entire NestedScrollView, without an issue in editing ?
EDIT: since the original app is a bit more complex, having some views at the bottom (inside what is like a toolbar) that auto-hide when you are not in focus on the bottom EditText , this made the answer I've found not to work.
Also, I've accidentally granted the bounty to the wrong answer, so here's a new bounty, on the more complex POC. The question stays the same. The NestedScrollView should remain on the same place, without scrolling when focusing on the bottom EditText.
<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) } } }
try this android:windowSoftInputMode="adjustResize" in your activity in manifest file.
The most reliable way to do this is using UI. setReadOnly(myEditText, true) from this library. There are a few properties that have to be set, which you can check out in the source code.
Advertisements. A EditText is an overlay over TextView that configures itself to be editable. It is the predefined subclass of TextView that includes rich editing capabilities.
In android, we can set the text of EditText control either while declaring it in Layout file or by using setText() method in Activity file.
I got some workaround for this, by wrapping the bottom EditText with a layout that will grant it focus.
Doesn't require much code at all
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) } } } }
manifest
<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>
You should be able to achieve what you want by calculating the minLines
based on the height of the screen. See the example activity and layout below.
You'll need to type quite a bit of text to use up the minimum lines and grow beyond the height of the screen to start the scrolling behavior, but you can circumvent this by adding a few constant lines to the minLines
calculation
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); } }
Here is the layout
<?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>
EDIT
I recreated your solution and you can correct the focus issue by setting this listener to your EditText. It works by overriding the scroll action when the Edit Text gets the focus, to only scroll enough to make the cursor visible.
contentEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View view, boolean hasFocus) { if(hasFocus){ nestedScrollView.scrollTo(0, 0); } } });
EDIT 2
I've updated my answer to reflect the changes with the new bounty, this should be pretty close to what you need, if I've understood the question properly.
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); } }); } }
Here is the new layout
<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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With