Подтвердить что ты не робот

Пользовательский повернутый вид EditText с рабочим выбором, расположением курсора и т.д.

Что я хочу делать

Я хочу сделать повернутое и перевернутое представление EditText, которое имеет все свойства обычного вида EditText.

Моя проблема

Я успешно сделал (с большой помощью от пользователей SO) настраиваемое представление EditText, которое поворачивается и переворачивается. Это было сделано путем переопределения метода onDraw. Однако курсор и подсветка исчезли, и событие longtouch все еще указывает исходную позицию текста. В принципе, представление было перерисовано, но событий касания не было.

Как я могу также активировать сенсорные события, подсветку и курсор?

Что я прочитал

Шкала EditText с выбором (Аналогичная проблема, но не совсем такая.)

Как создать пользовательский Edittext, чтобы он выглядел как 45 градусов, повернутый в android (@CommonsWare отметил для одного решения, что дополнительная работа должна быть сделано с сенсорными событиями. Что это за работа?)

http://developer.android.com/training/graphics/opengl/touch.html (полезно, но я не понимаю, как его применять в этой ситуации.)

Что я пробовал

Я сделал собственное представление, которое расширяет EditText. В нем overrode метод onDraw для поворота и переворота холста. Я переопределил onMeasure, чтобы сделать представление правильными размерами для макета.

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.widget.EditText;

public class MongolEditText extends EditText {

// Constructors
public MongolEditText(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}
public MongolEditText(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}
public MongolEditText(Context context) {
    super(context);
    init();
}

// This class requires the mirrored Mongolian font to be in the assets/fonts folder
private void init() {
    Typeface tf = Typeface.createFromAsset(getContext().getAssets(),
            "fonts/MongolChagaanMirrored.ttf");
    setTypeface(tf);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(heightMeasureSpec, widthMeasureSpec);
    setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}

@Override
protected void onDraw(Canvas canvas) {
    TextPaint textPaint = getPaint();
    textPaint.setColor(getCurrentTextColor());
    textPaint.drawableState = getDrawableState();

    canvas.save();

    canvas.translate(getWidth(), 0);
    canvas.rotate(90);
    canvas.translate(0, getWidth());
    canvas.scale(1, -1);

    canvas.translate(getCompoundPaddingLeft(), getExtendedPaddingTop());

    getLayout().draw(canvas);
    canvas.restore();
}
}

Для макета xml нет ничего особенного.

(Update) Этот вопрос является еще одной попыткой, но в конце концов я не смог заставить его работать: Необходимо ли переопределить invalidateDrawable() в дополнение к onDraw()?

Дальнейшее объяснение

Если вам интересно, почему в мире я хочу повернуть и перевернуть вид EditText, вот почему. Традиционный монгольский язык написан вертикально в столбцах слева направо. В сочетании с вертикально отраженным монгольским шрифтом, поворачивая текст на 90 градусов по часовой стрелке и переворачивая его, получается читаемый вывод с правильной оберткой линии.

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

Где я сейчас смотрю

(обновление)

Я думал о создании пользовательского представления (который расширяет View) с нуля, чтобы создать нечто вроде TextView. Этот TextView может быть обновлен из приложений, чтобы действовать как вид EditText. В этом случае мне нужно будет только поворачивать текст на 90 градусов с помощью обычного шрифта, но не переворачивать его. Тем не менее, я должен был бы сделать свою собственную линию.

Однако, прочитав ответ @Chitrang, я думаю, что могу сделать что-то подобное, просто расширив TextView. Тогда я могу избежать проблем с выполнением моей собственной линии.

Обновление изображения

enter image description here

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

4b9b3361

Ответ 1

Update

Я закончил разработку вертикального script MongolEditText с нуля. Он доступен в составе mongol-library.

Здесь он используется с двумя разными сторонними клавиатурами.

введите описание изображения здесь

Старый ответ

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

У меня есть немигающий курсор, который реагирует на события касания, но подсветка по-прежнему не поддерживается. Вот код:

public class MongolTextView extends TextView {

    private TextPaint textPaint;
    private Paint cursorPaint = new Paint();
    private boolean mCursorIsVisible;
    private CursorTouchLocationListener listener;

    // Naming is based on pre-rotated/mirrored values
    private float mCursorBaseY;
    private float mCursorBottomY;
    private float mCursorAscentY; // This is a negative number
    private float mCursorX;

    private static final float CURSOR_THICKNESS = 2f; 

    // Constructors
    public MongolTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

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

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

    // This class requires the mirrored Mongolian font to be in the assets/fonts folder
    private void init() {
        //Typeface tf = Typeface.createFromAsset(getContext().getAssets(),
        //      "fonts/ChimeeWhiteMirrored.ttf");
        //setTypeface(tf);

        // Use the above commented code is using a single font in another application 
        Typeface tf = FontCache.get(SettingsActivity.FONT_DEFAULT, getContext());
        if(tf != null) {
            setTypeface(tf);
        }

        this.mCursorIsVisible = true;

        cursorPaint.setStrokeWidth(CURSOR_THICKNESS);
        cursorPaint.setColor(Color.BLACK); // TODO should be same as text color

    }

    // This interface may be deleted if touch functionality is not needed
    public interface CursorTouchLocationListener {

        /**
         * Returns the touch location to be used for the cursor so you can update the insert
         * location in a text string.
         * 
         * @param glyphIndex
         *            You will need to translate glyphIndex into a Unicode index if you are using a
         *            Unicode string.
         */
        public void onCursorTouchLocationChanged(int glyphIndex);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // swap the height and width
        super.onMeasure(heightMeasureSpec, widthMeasureSpec);
        setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        textPaint = getPaint();
        textPaint.setColor(getCurrentTextColor());
        textPaint.drawableState = getDrawableState();

        canvas.save();

        // flip and rotate the canvas
        canvas.translate(getWidth(), 0);
        canvas.rotate(90);
        canvas.translate(0, getWidth());
        canvas.scale(1, -1);
        canvas.translate(getCompoundPaddingLeft(), getExtendedPaddingTop());

        // draw the cursor
        if (mCursorIsVisible) {
            canvas.drawLine(mCursorX, mCursorBottomY, mCursorX, mCursorBaseY + mCursorAscentY,
                    cursorPaint);
        }

        getLayout().draw(canvas);

        canvas.restore();
    }

    public void showCursor(boolean visible) {
        mCursorIsVisible = visible;
        this.invalidate();
        // TODO make the cursor blink
    }

    public void setCursorColor(int color) {
        cursorPaint.setColor(color);
    }

    public void setCursorLocation(int characterOffset) {

        Layout layout = this.getLayout();

        if (layout!=null){

            try {
                // This method is giving a lot of crashes so just surrounding with 
                // try catch for now

                int line = layout.getLineForOffset(characterOffset);
                mCursorX = layout.getPrimaryHorizontal(characterOffset);
                mCursorBaseY = layout.getLineBaseline(line);
                mCursorBottomY = layout.getLineBottom(line);
                mCursorAscentY = layout.getLineAscent(line);

                this.invalidate();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    public class InputWindowTouchListener implements OnTouchListener {
        @Override
        public boolean onTouch(View view, MotionEvent event) {

            Layout layout = ((TextView) view).getLayout();

            // swapping x and y for touch events
            int y = (int) event.getX();
            int x = (int) event.getY();

            if (layout != null) {

                int line = layout.getLineForVertical(y);
                int offset = layout.getOffsetForHorizontal(line, x);

                mCursorX = layout.getPrimaryHorizontal(offset);
                mCursorBaseY = layout.getLineBaseline(line);
                mCursorBottomY = layout.getLineBottom(line);
                mCursorAscentY = layout.getLineAscent(line);
                //mCursorHeightY = layout.getLineTop(line);

                view.invalidate();

                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    //handler.postDelayed(mLongPressed, 1000);
                    listener.onCursorTouchLocationChanged(offset);
                    break;
                case MotionEvent.ACTION_UP:
                    //handler.removeCallbacks(mLongPressed);
                    // notify the host activity of the new cursor location

                    break;
                }

            }

            return false;
        }

    }

    public void setCursorTouchLocationListener(CursorTouchLocationListener listener) {
        this.listener = listener;
    }
}

Не стесняйтесь добавлять свой собственный ответ, если у вас есть что-то лучше или сделайте комментарий, если у вас есть что добавить для улучшения этого (добавление подсветки, включение курсора и т.д.). Самая последняя версия этого кода должна быть на github.

Ответ 2

Пытался получить частичное решение с незначительными изменениями, проверьте, хотите ли вы.

1) Установите андроид: gravity = "top | left" в объявлении edittext внутри xml.

2) Заметил, что без метода super вызывается внутри метода onDraw, не может показывать курсор. Поэтому я позвонил,

super.onDraw(canvas);

вместо

getLayout().draw(canvas);

3). Для событий касания я попытался поменять координаты x и y. Так что вы можете иметь курсор в соответствии с событием касания. (Просто попробовал, и он работал, ему повезло:))

@Override
public boolean onTouchEvent(MotionEvent event) {
    // TODO Auto-generated method stub
    event.setLocation(event.getY(), event.getX());
    return super.onTouchEvent(event);
}

Прокомментируйте эту строку внутри метода onDraw, для точного события касания (найдено методом проб и ошибок).

canvas.translate(getCompoundPaddingLeft(), getExtendedPaddingTop());

4) Я ничего не мог сказать об подсветке или выборе текста.

?) Другое решение:. Если вы считаете, что некоторые из них поддерживают RTL-язык работайте над edittext, тогда вам просто нужно повернуть его. Но, к сожалению, он не работает должным образом с Android. Ссылка: Как обрабатывать языки RTL в версиях Android до 4.2? и Настройки Android с TextView для текста на иврите?

Ответ 3

Для вращения EditText для атрибута есть атрибут. Это просто и легко использовать. Это может помочь вам, я думаю.

<EditText
    android:id="@+id/editTextNumber"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:rotation="90"
    android:layout_marginBottom="10dp"
    android:hint="Enter Mobile Number"
    android:textAppearance="?android:attr/textAppearanceLarge" />

Ответ 4

Все гораздо проще. Все, что вам нужно, уже готово. Класс: http://developer.android.com/reference/android/view/View.html#setRotation(float) Немного более сложное решение, если предыдущий не работает для вас по какой-то причине: http://developer.android.com/reference/android/view/animation/RotateAnimation.html Он также используется для поворота представлений (но в большинстве случаев он анимирован, но вы можете использовать его с нулевой продолжительностью перехода).

Пожалуйста, дайте мне знать в случае, если у вас есть дополнительные вопросы (угадайте, нет, есть метод самообучения и класс).

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

Надеюсь, что это поможет!

Ответ 5

Попробуйте следующее:

<EditText
        android:id="@+id/ed1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView1"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="47dp"
        android:digits="1234567890"
        android:ems="10"
        android:singleLine="true"
        android:cursorVisible="true"
        android:hint="Refreshing time in ms" />