Выбранный прослушиватель текста в EditText Android [дубликат]

Вы могли использовать несколько запросов, которые используют Take и Skip , но это добавит слишком много итераций на Исходный список, я считаю.

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

public static IEnumerable> GetEnumerableOfEnumerables(
  IEnumerable enumerable, int groupSize)
{
   // The list to return.
   List list = new List(groupSize);

   // Cycle through all of the items.
   foreach (T item in enumerable)
   {
     // Add the item.
     list.Add(item);

     // If the list has the number of elements, return that.
     if (list.Count == groupSize)
     {
       // Return the list.
       yield return list;

       // Set the list to a new list.
       list = new List(groupSize);
     }
   }

   // Return the remainder if there is any,
   if (list.Count != 0)
   {
     // Return the list.
     yield return list;
   }
}

Затем вы можете вызвать это, и LINQ включен так, вы можете выполнять другие операции над результирующими последовательностями.


В ответ на ответ Сэма , я чувствовал, что существует более простой способ сделать это без:

  • Итерирование по списку снова (что я не делал изначально)
  • Материализация элементов в группах перед выпуском фрагмента (для больших фрагментов элементов возникли проблемы с памятью)
  • Весь код, отправленный Сэм

Итак, вот еще один проход, который я кодировал в методе расширения до IEnumerable Chunk:

public static IEnumerable> Chunk(this IEnumerable source, 
    int chunkSize)
{
    // Validate parameters.
    if (source == null) throw new ArgumentNullException("source");
    if (chunkSize <= 0) throw new ArgumentOutOfRangeException("chunkSize",
        "The chunkSize parameter must be a positive value.");

    // Call the internal implementation.
    return source.ChunkInternal(chunkSize);
}

Ничего удивительного там, просто базовая проверка ошибок.

Переход к ChunkInternal:

private static IEnumerable> ChunkInternal(
    this IEnumerable source, int chunkSize)
{
    // Validate parameters.
    Debug.Assert(source != null);
    Debug.Assert(chunkSize > 0);

    // Get the enumerator.  Dispose of when done.
    using (IEnumerator enumerator = source.GetEnumerator())
    do
    {
        // Move to the next element.  If there's nothing left
        // then get out.
        if (!enumerator.MoveNext()) yield break;

        // Return the chunked sequence.
        yield return ChunkSequence(enumerator, chunkSize);
    } while (true);
}

В принципе , он получает IEnumerator и вручную выполняет итерацию через каждый элемент. Он проверяет, есть ли какие-либо элементы, которые в настоящее время перечислены. После того, как каждый фрагмент перечислит, если не осталось никаких элементов, он выйдет из строя.

Как только он обнаруживает, что есть элементы в последовательности, он делегирует ответственность за внутреннюю реализацию IEnumerable до ChunkSequence:

private static IEnumerable ChunkSequence(IEnumerator enumerator, 
    int chunkSize)
{
    // Validate parameters.
    Debug.Assert(enumerator != null);
    Debug.Assert(chunkSize > 0);

    // The count.
    int count = 0;

    // There is at least one item.  Yield and then continue.
    do
    {
        // Yield the item.
        yield return enumerator.Current;
    } while (++count < chunkSize && enumerator.MoveNext());
}

Поскольку MoveNext уже вызывается на IEnumerator, переданном в ChunkSequence, он возвращает элемент, возвращенный Current , а затем увеличивает счетчик, чтобы никогда не возвращать больше, чем chunkSize элементов и переходить к следующему элементу в последовательности после каждой итерации (но закорочен, если количество полученных элементов превышает размер куска).

Если никаких элементов не осталось, то метод InternalChunk сделает другой проход во внешнем цикле, но когда MoveNext вызывается второй раз, он все равно вернет false, в качестве в документации (выделенное мое):

Если MoveNext передает конец коллекции, перечислитель помещается после последнего элемента в коллекции, а MoveNext возвращает false. Когда перечислитель находится в этой позиции, последующие вызовы MoveNext также возвращают false до тех пор, пока не вызывается Reset.

В этот момент цикл прерывается, и последовательность последовательностей прекращается.

Это простой тест:

static void Main()
{
    string s = "agewpsqfxyimc";

    int count = 0;

    // Group by three.
    foreach (IEnumerable g in s.Chunk(3))
    {
        // Print out the group.
        Console.Write("Group: {0} - ", ++count);

        // Print the items.
        foreach (char c in g)
        {
            // Print the item.
            Console.Write(c + ", ");
        }

        // Finish the line.
        Console.WriteLine();
    }
}

Выход:

Group: 1 - a, g, e,
Group: 2 - w, p, s,
Group: 3 - q, f, x,
Group: 4 - y, i, m,
Group: 5 - c,

Важно отметить, что не работает, если вы не сливайте всю последовательность потомков или не разбивайте их в любой точке родительской последовательности. Это важный аспект, но если ваш случай использования заключается в том, что вы будете потреблять каждый элемент последовательности последовательностей, то это будет работать для вас.

Кроме того, он будет делать странные вещи, если вы играете с порядком, так же, как Сэм делал в какой-то момент .

7
задан Peter 26 February 2013 в 16:35
поделиться

2 ответа

Я думаю, вы можете найти свой ответ здесь:

Слушатель для выбора текста Android

Ключевой термин, который вы ищете здесь, ActionMode, если ваша цель сотовая или более новая.

API docs (прокрутите вниз до «с использованием режима контекстного действия») хорошая работа по разъяснению вещей, как только вы найдете то, что ищете, что является самым большим препятствием для их использования, но в основном то, что вам нужно сделать, это следующее:

  1. установите EditText для выбора (android:textIsSelectable="true" или setTextIsSelectable(true);
  2. Внедрите интерфейс ActionMode.Callback и укажите свои собственные пункты меню.

ПРИМЕЧАНИЕ: как упомянутый выше, это работает только для уровня API 11+. Если вы ориентируетесь на более ранние платформы, получение событий для выбора текста намного сложнее.

2
ответ дан Remy Lebeau 21 August 2018 в 00:58
поделиться

в .xml:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textIsSelectable="true" />

в .class:

textview.setCustomSelectionActionModeCallback(new callback(textview));
...
public class callback implements Callback {

    private TextView mTextView;

    public callback(TextView text) {
        this.mTextView = text;

    }

    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        int start = mTextView.getSelectionStart();
        int end = mTextView.getSelectionEnd();
        Spannable wordtoSpan = (Spannable) mTextView.getText();

        switch (item.getItemId()) {

        case R.id.item_blue:
            wordtoSpan.setSpan(new BackgroundColorSpan(Color.BLUE), start
                    , end,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        singlenton.getInstance().getDatabase().createMarkText(mTextView,Color.BLUE);
            return true;

        case R.id.item_green:
            wordtoSpan.setSpan(new BackgroundColorSpan(Color.GREEN), start, end,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            singlenton.getInstance().getDatabase().createMarkText(mTextView,Color.GREEN);
            return true;

        case R.id.item_red:
            wordtoSpan.setSpan(new BackgroundColorSpan(Color.RED), start, end,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            singlenton.getInstance().getDatabase().createMarkText(mTextView,Color.RED);
            return true;
        case R.id.item_yellow:
            wordtoSpan.setSpan(new BackgroundColorSpan(Color.YELLOW), start, end,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            singlenton.getInstance().getDatabase().createMarkText(mTextView,Color.YELLOW);
            return true;
        case R.id.item_erase:
            wordtoSpan.setSpan(new BackgroundColorSpan(Color.TRANSPARENT), start, end,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            singlenton.getInstance().getDatabase().createMarkText(mTextView,Color.TRANSPARENT);
            return true;
        }
        return false;
    }

    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        mode.setTitle("Selecione a cor");
        mode.getMenuInflater().inflate(R.menu.menu_text_context, menu);

        return true;
    }

    @Override
    public void onDestroyActionMode(ActionMode mode) {

    }

    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        menu.removeItem(android.R.id.selectAll);
        // Remove the "cut" option
        menu.removeItem(android.R.id.cut);
        // Remove the "copy all" option
        menu.removeItem(android.R.id.copy);
        return true;
    }

}
1
ответ дан rsicarelli 21 August 2018 в 00:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: