Android 带有工作选择、光标位置等的自定义旋转编辑文本视图 我想做什么
我想创建一个旋转和翻转的EditText视图,该视图具有普通EditText视图的所有属性 我的问题 在SO用户的帮助下,我成功地创建了一个自定义的EditText视图,该视图可以旋转和翻转。这是通过重写onDraw方法实现的。但是,光标和高亮显示消失,长触事件仍然指示原始文本位置。基本上,视图被重新绘制,但触摸事件没有 如何使触摸事件、高亮显示和光标也旋转和翻转 我所读的 (类似的问题,但不完全相同。) (@commonware在一个解决方案中指出,需要对触摸事件进行添加工作。这是什么工作?) (有帮助,但我不知道如何在这种情况下应用它。) 我试过的 我创建了一个扩展EditText的自定义视图。在其中,它覆盖了onDraw方法来旋转和翻转画布。为了使视图具有正确的布局尺寸,我超出了测量范围Android 带有工作选择、光标位置等的自定义旋转编辑文本视图 我想做什么,android,android-edittext,rotation,mongolian-vertical-script,Android,Android Edittext,Rotation,Mongolian Vertical Script,我想创建一个旋转和翻转的EditText视图,该视图具有普通EditText视图的所有属性 我的问题 在SO用户的帮助下,我成功地创建了一个自定义的EditText视图,该视图可以旋转和翻转。这是通过重写onDraw方法实现的。但是,光标和高亮显示消失,长触事件仍然指示原始文本位置。基本上,视图被重新绘制,但触摸事件没有 如何使触摸事件、高亮显示和光标也旋转和翻转 我所读的 (类似的问题,但不完全相同。) (@commonware在一个解决方案中指出,需要对触摸事件进行添加工作。这是什么工作?)
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没有什么特别之处
(更新)这个问题是另一次尝试,但最终我无法让它发挥作用:
进一步解释
如果您想知道为什么我要旋转和翻转EditText视图,下面是原因。传统蒙古语是从左到右垂直书写的。与垂直镜像的蒙古文字体相结合,将文本顺时针旋转90度并翻转,可产生具有正确换行的可读输出
这不是一个模糊或孤立的问题。传统蒙古语应用程序的用户有数百万,但安卓应用程序的用户寥寥无几。其中,我还没有找到任何开源的。如果我能让它工作,我想让代码可供其他开发人员使用
我现在看的地方(更新)
我正在考虑从头创建一个自定义视图(扩展视图
),以创建类似文本视图
的东西。此TextView
可以从应用程序中更新,使其与EditText
视图类似。在这种情况下,我只需要用普通字体将文本旋转90度,而不需要翻转它。然而,我将不得不做我自己的线包装
然而,在阅读了@Chitrang的答案后,我想我可以通过扩展文本视图来做类似的事情。这样我就可以避免自己绕线的麻烦了
图片更新
蒙古语从上到下、从左到右书写。现在我用这个键盘在文本周围移动光标,但我希望能够触摸屏幕将光标移动到某个位置 尝试通过微小的更改获得部分解决方案,请检查您是否需要 1)在xml内部的edittext声明中设置android:gravity=“top | left” 2)注意到,如果在onDraw方法中没有super方法调用,则无法显示光标。 所以我打电话
super.onDraw(canvas);
相反
getLayout().draw(canvas);
3)对于触摸事件,我尝试交换x和y坐标。
这样,您就可以根据触摸事件使用光标。(刚刚尝试过,它就工作了,幸运的是:)
在onDraw方法中注释这一行,以获得精确的触摸事件(通过尝试和错误发现)
4)我无法突出显示或选择文本
?)另一个解决方案:如果您这样认为,请介绍如何获得RTL语言支持
处理edittext,然后只需旋转它。但不幸的是,它不能与android正常工作。
参考:
而且事情要简单得多。您所需的一切都已内置在View类中: 如果由于某种原因前一个解决方案不适用于您,则更复杂的解决方案是: 它还用于视图的旋转(但在大多数情况下设置了动画,但可以使用零过渡持续时间) 如果你还有其他问题,请告诉我(猜没有-有自我解释的方法和课程) 只旋转画布-只旋转屏幕上的图像。setRotation还处理所有事件、布局流等,因此它在您的情况下应该可以正常工作
希望能有帮助 编辑文本有一个属性用于旋转。它很简单,也很容易使用。我想它可能会对你有所帮助
<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" />
试试这个:
<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" />
更新
我最终从头开始开发了一个垂直脚本。它作为的一部分提供
在这里,它与两个不同的第三方键盘一起使用
旧答案
这仍然是一项正在进行的工作,所以我不会将其标记为已解决,但让我发布到目前为止的内容。它做了我想做的大部分事情。基本上,我使用的是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;
}
}
如果您有更好的答案,请随意添加您自己的答案,如果您有改进的地方(添加高亮显示、让光标闪烁等),请发表评论。此代码的最新版本应处于启用状态。您是否可以共享当前结果和预期结果的图片?你听说过一部电影吗?它能说千言万语我喜欢蒙古牛肉干,但我无法理解你对它过去的书写方式的看法……:)旋转对您没有帮助,因为EditText->TextView在旋转之前已使用宽度-高度进行初始化。我正在研究TextView代码并进行实验:)@AZ_u感谢您的兴趣。我在上面添加了一个截图。虽然最终我想得到一些更全面的东西,但现在我会很满意,只要我能碰上一个词,就可以了
<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" />
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;
}
}