многострочный текст редактирования, где детали недоступны для редактирования, такие как заполнение пробелов - PullRequest
0 голосов
/ 13 октября 2018

Мне нужно иметь представление, которое содержит textview и edittext.

Пример:

Yay! you made it to ______ We should hang out! feel ____ to follow me. 

Выше "_____" может быть любой длины, и в конце он должен выглядеть как параграф.Остальная часть приведенного выше текста не подлежит изменению.Так же, как заполните пробелы.

image image

Ответы [ 3 ]

0 голосов
/ 24 октября 2018

Solution one

Попробуйте использовать flexbox-layout - https://github.com/google/flexbox-layout.

Solution Two

Использовать textWatcher

Решение третье

  • Используйте html, css и javascript для создания простой веб-страницы.
  • Используйте webview для загрузки html-файла.
0 голосов
/ 29 октября 2018

С моей точки зрения, виджет для заполнения пустых полей должен выполнять следующие действия:

  1. Разрешать изменение только определенных идентифицированных частей текста.Остальная часть текста заблокирована.
  2. Не разрешать перемещение курсора в заблокированный текст.
  3. Переход от строки к строке, как EditText.
  4. Обобщается с помощью переменного размещенияиз пробелов.

Вот реализация такого виджета, основанная на EditText.Редактируемые пролеты устанавливаются с использованием диапазона (BlanksSpan), расширенного с StyleSpan.Пустой интервал обозначается пятью подчеркиваниями ("_____") в тексте.Движение курсора контролируется в OnSelectionChanged() и различных EditText обратных вызовах.Изменения в тексте отслеживаются с помощью TextWatcher, и там вносятся корректировки в отображаемый текст.

Вот видео используемого виджета:

enter image description here

FillInBlanksEditText.java

public class FillInBlanksEditText extends android.support.v7.widget.AppCompatEditText  
    implements View.OnFocusChangeListener, TextWatcher {  
    private int mLastSelStart;  
    private int mLastSelEnd;  
    private BlanksSpan mSpans[];  
    private Editable mUndoChange;  
    private BlanksSpan mWatcherSpan;  

    public FillInBlanksEditText(Context context) {  
        super(context);  
        init();  
    }  

    public FillInBlanksEditText(Context context, AttributeSet attrs) {  
        super(context, attrs);  
        init();  
    }  

    public FillInBlanksEditText(Context context, AttributeSet attrs, int defStyleAttr) {  
        super(context, attrs, defStyleAttr);  
        init();  
    }  

    private void init() {  
        mSpans = setSpans();  
        setOnFocusChangeListener(this);  
    }  

    @Override  
  public void onRestoreInstanceState(Parcelable state) {  
        mSpans = null;  
        super.onRestoreInstanceState(state);  
        Editable e = getEditableText();  
        mSpans = e.getSpans(0, e.length(), BlanksSpan.class);  
    }  

    @Override  
  public void onFocusChange(View v, boolean hasFocus) {  
        if (hasFocus) {  
            addTextChangedListener(this);  
            if (findInSpan(getSelectionStart(), getSelectionEnd()) != null) {  
                mLastSelStart = getSelectionStart();  
                mLastSelEnd = getSelectionEnd();  
            } else if (findInSpan(mLastSelStart, mLastSelEnd) == null) {  
                setSelection(getEditableText().getSpanStart(mSpans[0]));  
            }  
        } else {  
            removeTextChangedListener(this);  
        }  
    }  

    @Override  
  protected void onSelectionChanged(int selStart, int selEnd) {  
        if (!isFocused() || mSpans == null ||  
            (getSelectionStart() == mLastSelStart && getSelectionEnd() == mLastSelEnd)) {  
            return;  
        }  

        // The selection must be completely within a Blankspan.  
  final BlanksSpan span = findInSpan(selStart, selEnd);  
        if (span == null) {  
            // Current selection is not within a Blankspan. Restore selection to prior location.  
  moveCursor(mLastSelStart);  
        } else if (selStart > getEditableText().getSpanStart(span) + span.getDataLength()) {  
            // Acceptable location for selection (within a Blankspan).  
 // Make sure that the cursor is at the end of the entered data.  mLastSelStart = getEditableText().getSpanStart(span) + span.getDataLength();  
            mLastSelEnd = mLastSelStart;  
            moveCursor(mLastSelStart);  

        } else {  
            // Just capture the placement.  
  mLastSelStart = selStart;  
            mLastSelEnd = selEnd;  
        }  
        super.onSelectionChanged(mLastSelStart, mLastSelEnd);  
    }  

    // Safely move the cursor without directly invoking setSelection from onSelectionChange.  
  private void moveCursor(final int selStart) {  
        post(new Runnable() {  
            @Override  
  public void run() {  
                setSelection(selStart);  
            }  
        });  
        // Stop cursor form jumping on move.  
  getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {  
            @Override  
  public boolean onPreDraw() {  
                getViewTreeObserver().removeOnPreDrawListener(this);  
                return false;  
            }  
        });  
    }  

    @Nullable  
  private BlanksSpan findInSpan(int selStart, int selEnd) {  
        for (BlanksSpan span : mSpans) {  
            if (selStart >= getEditableText().getSpanStart(span) &&  
                selEnd <= getEditableText().getSpanEnd(span)) {  
                return span;  
            }  
        }  
        return null;  
    }  

    // Set up a Blankspan to cover each occurrence of BLANKS_TOKEN.  
  private BlanksSpan[] setSpans() {  
        Editable e = getEditableText();  
        String s = e.toString();  
        int offset = 0;  
        int blanksOffset;  

        while ((blanksOffset = s.substring(offset).indexOf(BLANKS_TOKEN)) != -1) {  
            offset += blanksOffset;  
            e.setSpan(new BlanksSpan(Typeface.BOLD), offset, offset + BLANKS_TOKEN.length(),  
                      Spanned.SPAN_INCLUSIVE_INCLUSIVE);  
            offset += BLANKS_TOKEN.length();  
        }  
        return e.getSpans(0, e.length(), BlanksSpan.class);  
    }  

    // Check change to make sure that it is acceptable to us.  
  @Override  
  public void beforeTextChanged(CharSequence s, int start, int count, int after) {  
        mWatcherSpan = findInSpan(start, start + count);  
        if (mWatcherSpan == null) {  
            // Change outside of a Blankspan. Just put things back the way they were.  
 // Do this in afterTextChaanged.  mUndoChange = Editable.Factory.getInstance().newEditable(s);  
        } else {  
            // Change is OK. Track data length.  
  mWatcherSpan.adjustDataLength(count, after);  
        }  
    }  

    @Override  
  public void onTextChanged(CharSequence s, int start, int before, int count) {  
        // Do nothing...  
  }  

    @Override  
  public void afterTextChanged(Editable s) {  
        if (mUndoChange == null) {  
            // The change is legal. Modify the contents of the span to the format we want.  
  CharSequence newContents = mWatcherSpan.getFormattedContent(s);  
            if (newContents != null) {  
                removeTextChangedListener(this);  
                int selection = getSelectionStart();  
                s.replace(s.getSpanStart(mWatcherSpan), s.getSpanEnd(mWatcherSpan), newContents);  
                setSelection(selection);  
                addTextChangedListener(this);  
            }  
        } else {  
            // Illegal change - put things back the way they were.  
  removeTextChangedListener(this);  
            setText(mUndoChange);  
            mUndoChange = null;  
            addTextChangedListener(this);  
        }  
    }  

    @SuppressWarnings("WeakerAccess")  
    public static class BlanksSpan extends StyleSpan {  
        private int mDataLength;  

        public BlanksSpan(int style) {  
            super(style);  
        }  

        @SuppressWarnings("unused")  
        public BlanksSpan(@NonNull Parcel src) {  
            super(src);  
        }  

        public void adjustDataLength(int count, int after) {  
            mDataLength += after - count;  
        }  

        @Nullable  
  public CharSequence getFormattedContent(Editable e) {  
            if (mDataLength == 0) {  
                return BLANKS_TOKEN;  
            }  
            int spanStart = e.getSpanStart(this);  
            return (e.getSpanEnd(this) - spanStart > mDataLength)  
                ? e.subSequence(spanStart, spanStart + mDataLength)  
                : null;  
        }  

        public int getDataLength() {  
            return mDataLength;  
        }  

    }  

    @SuppressWarnings({"FieldCanBeLocal", "unused"})  
    private static final String TAG = "FillInBlanksEditText";  
    private static final String BLANKS_TOKEN = "_____";  

}

activity_main.java
Пример макета.

<android.support.constraint.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.example.fillintheblanks.FillInBlanksEditText
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:background="@android:color/transparent"
        android:inputType="textMultiLine"
        android:padding="16dp"
        android:text="Yay! You made it to _____. We should hang out! Feel _____ to follow me."
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.example.fillintheblanks.FillInBlanksEditText
        android:id="@+id/editText2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:background="@android:color/transparent"
        android:inputType="textMultiLine"
        android:padding="16dp"
        android:text="_____ says that it is time to _____. Are you _____?"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/editText" />

</android.support.constraint.ConstraintLayout>

Несколько вещей, на которые следует обратить внимание:

  1. В извлеченном режиме размещение курсора переключается, если касание выполняется за пределами BlanksSpan.Вещи все еще работают, но немного плохо себя ведут.
  2. Длина полей пробелов фиксирована, но ее можно сделать переменной длины при некоторой дополнительной работе.
  3. Режим действия в элементе управления требует некоторого количестваработа на основе требований.
0 голосов
/ 24 октября 2018

многострочный текст редактирования, где детали недоступны для редактирования, такие как заполнение пробелов

Вы можете использовать TextWatcher() для этого требования

Попробуйте это, он - маленькая работа вокруг этого

MainActivity

public class MainActivity extends AppCompatActivity {


    EditText myEditText;
    String startText = "I'm The First Part";
    String lastText = "I'm The Last Part";

    SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();

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

        final SpannableStringBuilder firstStringBuilder = new SpannableStringBuilder(startText);
        final SpannableStringBuilder lastStringBuilder = new SpannableStringBuilder(lastText);

        StyleSpan firstStyleSpan = new StyleSpan(android.graphics.Typeface.BOLD);

        firstStringBuilder.setSpan(firstStyleSpan, 0, firstStringBuilder.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); // make first 4 characters Bold
        lastStringBuilder.setSpan(firstStyleSpan, 0, lastStringBuilder.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); // make first 4 characters Bold

        myEditText = findViewById(R.id.myEditText);


        spannableStringBuilder.append(firstStringBuilder);
        spannableStringBuilder.append("   ");
        spannableStringBuilder.append(lastStringBuilder);

        myEditText.setText(spannableStringBuilder);
        Selection.setSelection(myEditText.getText(), startText.length() + 1);

        myEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {


            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count,
                                          int after) {
                // TODO Auto-generated method stub

            }

            @Override
            public void afterTextChanged(Editable s) {

                if (!s.toString().startsWith(firstStringBuilder.toString())
                        || !s.toString().contains(lastText)) {
                    Log.e("StringBuilder_TAG", spannableStringBuilder.toString());

                    myEditText.setText(spannableStringBuilder);
                    Selection.setSelection(myEditText.getText(), myEditText.getText().length() - lastStringBuilder.length() - 1);
                } else {

                    spannableStringBuilder.clear();
                    spannableStringBuilder.append(s.toString());
                    Log.e("My_TAG", spannableStringBuilder.toString());

                }

            }
        });

    }


}

layout.activity_main

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">


    <EditText
        android:id="@+id/myEditText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent"
        android:padding="5dp" />


</LinearLayout>

Вот выходное видео с кодом выше https://www.youtube.com/watch?v=pfhUzLiFD6U

, используя приведенный выше код, вы можете сделать невозможным редактирование первой и последней частей editext

Примечание

Вы также можете использовать TextDrawable вот несколько ссылок для этого

Вы также можете создать пользовательский EditText для этого

Вы также можете использовать InputFilter

...