如何让EditText占用所需的空间,可以与上面的内容一起滚动?

时间:2018-03-21 13:23:36

标签: android android-edittext android-nestedscrollview

背景

我的布局顶部有一些视图,应该可以与它们下面的EditText一起滚动。

EditText占用了剩下的空间,占用了所需的空间。

以下是演示它的示例POC布局(此处仅使用了2个EditTexts):

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

我已经设置了一个背景框,可以直观地显示EditText的大小。

问题

我找到了很多我写的解决方案,但实际上没有一个能够很好地处理滚动。

我一直看到的,至少是其中一个问题:

  1. 无法滚动整个页面(只有EditText可以滚动,我正在努力避免),因此无法再访问顶部的视图。
  2. 当我输入文字时,插入符号可能会出现在可见区域之外
  3. 当我输入越来越多的行时,它不会滚动整个页面。仅在EditText本身。
  4. 我尝试了什么

    我尝试过这些解决方案:

    1. 全部来自herehereherehere。也许更多,但我没有保持足够的轨道......
    2. 我在清单中尝试了各种windowSoftInputMode值,并尝试在NestedScrollView中设置isNestedScrollingEnabled
    3. 尝试使用XML中的各种配置,让EditText占用所需的空间,以防止它在其中滚动。
    4. 问题

      如何让底层的EditText占用尽可能多的空间,并且仍然可以滚动整个NestedScrollView,而不会出现编辑问题?

      编辑:由于原始应用程序有点复杂,底部有一些视图(在工具栏内部),当你没有专注于底部的EditText时自动隐藏,这就得到了答案我发现没有工作。

      另外,我不小心把赏金给了错误的答案,所以这是一个新的赏金,在更复杂的POC上。问题保持不变。 NestedScrollView应该保留在同一个地方,而不是在关注底部的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)
              }
          }
      }
      

4 个答案:

答案 0 :(得分:15)

我得到了一些解决方法,通过将底部的EditText包装为可以为其提供焦点的布局。

根本不需要太多代码

<强> 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 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>

答案 1 :(得分:13)

您应该能够通过根据屏幕高度计算minLines来实现您想要的效果。请参阅下面的示例活动和布局。

您需要输入相当多的文本来消耗最小的行并超出屏幕的高度以开始滚动行为,但是您可以通过向{添加一些常量行来避免这种情况。 {1}}计算

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

编辑

我重新创建了您的解决方案,您可以通过将此侦听器设置为EditText来纠正焦点问题。它通过在编辑文本获得焦点时覆盖滚动操作来工作,仅滚动到足以使光标可见。

<?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>

编辑2

我已经更新了我的回答以反映新奖励的变化,如果我已经正确地理解了这个问题,这应该非常接近你所需要的。

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

这是新布局

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

答案 2 :(得分:3)

您可以通过更改layout.xml和MainActivity来实现预期结果。 更改layout_height并为layout_weight添加ConstraintLayout,如下所示:

    <?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是:

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

记录scrollX&amp;的当前值滚动Y NestedScrollView并按如下方式调整NestedScrollView

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

没有必要时它没有滚动。看截图: screen shot

答案 3 :(得分:1)

我意识到NestedScrollView在内容离开屏幕之前不会滚动。我做了一个黑客并在输入的文本后放了一些空行,以确保内容将超出当前屏幕。在EditText失去焦点之后,我删除了空行。

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