试图使文本控制台具有40列或字符 [英] trying to make a text console with 40 columns or characters
问题描述
我正在扩展MultiAutoCompleteTextView,并且将字体设置为此字体 Unicode字体
I am extending a MultiAutoCompleteTextView and I have the font set to this font Unicode font
这是我声明的xml
<jacs.apps.jacs.CustomViews.Console
android:id="@+id/auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:dropDownAnchor="@id/content_frame"
android:dropDownHeight="100dp"
android:layout_weight="1"
android:gravity="bottom"
android:inputType="textMultiLine|textNoSuggestions"
android:fontFamily="@font/unifont"
android:imeOptions="actionDone"
android:scrollbars="vertical"
android:scrollHorizontally="false"
android:singleLine="false"
android:typeface="monospace"
/>
这是我的课程
class Console : AppCompatMultiAutoCompleteTextView {
private var mCharHeight = 0
private var h: Int = 0
private var mIsSearchEnabled = true
protected val heightVisible: Int
get() {
val rect = Rect()
getWindowVisibleDisplayFrame(rect)
return rect.bottom - rect.top
}
constructor(context: Context) : super(context) {}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}
private fun refitText(text: String, textWidth: Int) {
val mTestPaint = Paint()
mTestPaint.set(this.paint)
if (textWidth <= 0)
return
val targetWidth = textWidth - this.paddingLeft - this.paddingRight
var hi = 100f
var lo = 2f
val threshold = 0.5f // How close we have to be
mTestPaint.set(this.paint)
while (hi - lo > threshold) {
val size = (hi + lo) / 2
mTestPaint.textSize = size
if (mTestPaint.measureText(text) >= targetWidth)
hi = size // too big
else
lo = size // too small
}
// Use lo so that we undershoot rather than overshoot
this.setTextSize(TypedValue.COMPLEX_UNIT_PX, lo)
Log.d("baseline", "textsize: $textSize")
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val parentWidth = MeasureSpec.getSize(widthMeasureSpec)
val height = measuredHeight
refitText("mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm", parentWidth)
this.setMeasuredDimension(parentWidth, height)
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
onDropDownChangeSize(w, h)
}
protected fun onDropDownChangeSize(w: Int, h: Int) {
val rect = Rect()
getWindowVisibleDisplayFrame(rect)
//Logger.debug(TAG, "onDropdownChangeSize: " + rect);
// 1/2 width of screen
dropDownWidth = (w * 0.5f).toInt()
// 0.5 height of screen
//setDropDownHeight((int) (h * 1f));
dropDownHeight = 300
this.h = h
Log.d("suggestions", "h : $h")
//change position
onPopupChangePosition()
}
fun setSearchEnabledTrue() {
mIsSearchEnabled = true
setSearchEnabled(true)
}
fun setSearchEnabled(isEnabled: Boolean) {
mIsSearchEnabled = isEnabled
}
override fun performFiltering(text: CharSequence, keyCode: Int) {
if (mIsSearchEnabled) {
super.performFiltering(text, keyCode)
}
}
override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
val conn = super.onCreateInputConnection(outAttrs)
outAttrs.imeOptions = outAttrs.imeOptions and EditorInfo.IME_FLAG_NO_ENTER_ACTION.inv()
return conn
}
override fun showDropDown() {
if (mIsSearchEnabled) {
onPopupChangePosition()
super.showDropDown()
}
}
protected fun invalidateCharHeight() {
mCharHeight = Math.ceil(paint.fontSpacing.toDouble()).toInt()
mCharHeight = paint.measureText("M").toInt()
}
protected fun onPopupChangePosition() {
try {
val layout = layout
invalidateCharHeight()
if (layout != null) {
val pos = selectionStart
val line = layout.getLineForOffset(pos)
val baseline = layout.getLineBaseline(line)
val ascent = layout.getLineAscent(line)
val bounds = Rect()
val textPaint = paint
val sample = "A"
textPaint.getTextBounds(sample, 0, sample.length, bounds)
val width = bounds.width() / sample.length
val x = layout.getPrimaryHorizontal(pos)
val y = (baseline + ascent).toFloat()
val offsetHorizontal = x.toInt() + getWidth()
dropDownHorizontalOffset = offsetHorizontal
val heightVisible = heightVisible
val offsetVertical = (y + mCharHeight - scrollY).toInt()
val tmp = -h + offsetVertical + dropDownHeight + mCharHeight
//if (tmp < heightVisible) {
//tmp = -h + ((offsetVertical*2 / (mCharHeight)) * (mCharHeight / 2))+(mCharHeight/2);
dropDownVerticalOffset = tmp
Log.d("suggestions", "tmp : $tmp")
//((Activity)(mContext)).setTitle("ov :"+offsetVertical +" ch "+mCharHeight+" tmp"+tmp +"h "+h+"p:"+pos);
// } else {
// tmp = offsetVertical - getDropDownHeight() - mCharHeight;
// setDropDownVerticalOffset(tmp);
// ((Activity)(mContext)).setTitle(" 2 tmp :"+tmp);
// }
// int pos = getSelectionStart();
// int line = layout.getLineForOffset(pos);
// int baseline = layout.getLineBaseline(line);
// int ascent = layout.getLineAscent(line);
//
// float x = layout.getPrimaryHorizontal(pos);
// float y = baseline + ascent;
//
// int offsetHorizontal = (int) x + mGutterWidth;
// setDropDownHorizontalOffset(offsetHorizontal);
//
// // int heightVisible = getHeightVisible();
// int offsetVertical = (int) ((y + mCharHeight) - getScrollY());
//
// int tmp = offsetVertical + getDropDownHeight() + mCharHeight;
//// if (tmp < heightVisible) {
// tmp = -(offsetVertical + mCharHeight) + ((offsetVertical / mCharHeight) * (mCharHeight / 2));
// setDropDownVerticalOffset(tmp);
//// } else {
//// tmp = offsetVertical - getDropDownHeight() - mCharHeight;
//// setDropDownVerticalOffset(tmp);
//// }
}
} catch (e: Exception) {
e.printStackTrace()
}
}
companion object {
private val MINIMAL_HEIGHT = 100
}
}
我正在尝试使每个设备的视图宽40个字符,并且该视图可以在许多不同的设备上运行,但是当我在分辨率为720X1560的仿真器上运行该视图时,它允许每行41个字符,而不是所需的40个字符.我试图找到一种方法来设置字体大小,以使每行有40个字符.
I am trying to make the view 40 characters wide for every device and it works on a bunch of different devices but when I run it on an emulator that's resolution is 720X1560 it lets 41 characters per row instead of the desired 40. I am trying to find a way to make the font size so that there are 40 characters per row.
编辑
放置android:paddingRight="35dp"
似乎可以解决问题,尽管id希望确定也不能使用换行符,因为我已经在使用它们进行特殊的解析
EDIT
putting android:paddingRight="35dp"
seemed to fix the problem although id like to know for sure also I cannot use newlines because I am already using them for a special kind of parsing
谢谢您的时间
推荐答案
我修改了refitText
方法,如下所示:
I modified refitText
method as below:
private fun refitText(columns: Int, textWidth: Int) {
val mTestPaint = Paint()
mTestPaint.set(this.paint)
if (textWidth <= 0)
return
val targetWidth = textWidth - this.paddingLeft - this.paddingRight
val maxTextSize = 1000000f
mTestPaint.textSize = maxTextSize
val maxCharWidth = mTestPaint.measureText("m")
var size = targetWidth * maxTextSize / (maxCharWidth * columns)
do {
mTestPaint.textSize = size
val realCharWidth = mTestPaint.measureText("m")
val requiredPadding = targetWidth - realCharWidth * columns;
if (requiredPadding >= 0) {
this.setPadding(this.paddingLeft + requiredPadding.toInt() / 2, this.paddingTop, this.paddingRight + requiredPadding.toInt() / 2, this.paddingBottom)
break
}
size *= 1 - (Math.abs(requiredPadding) / targetWidth)
} while (requiredPadding < 0)
this.setTextSize(TypedValue.COMPLEX_UNIT_PX, size)
Log.d("baseline", "textsize: $textSize")
}
字符宽度必须为像素的正整数,因为不可能在显示器上打开一个像素的一半,然后再关闭该像素的另一半. 假设您计算出一种字体大小,该字体大小可以在显示器中以720像素的宽度呈现39个字符.这意味着每个字符的宽度为18像素(720/39 = 18).另一方面,要渲染40个字符,您必须减小字体大小.在这种情况下,减小字体大小后,最大字符宽度可以为17个像素.现在,前39个字符将显示在663个像素上(39 * 17 = 663),仍然有57个空像素(720-663 = 57)足以在该行中渲染另外3个字符(57/17 = 3) .在这种情况下,您需要另一个限制.因此,您应该添加一些动态计算的填充,以控制一行中的字符数.
Character width must be a positive integer of pixels because it's impossible to turn half of a pixel on and turn another half of that pixel off on the Display. Suppose you calculated a font size that renders 39 characters in your display with 720 pixels width. It means each character's width is 18 pixels (720/39=18). In other hand, to render 40 charachters, you have to reduce the font size. In this case, after reducing font size, the maximum character width could be 17 pixels. Now the first 39 characters will be shown on 663 pixels (39*17=663) and there are still 57 empty pixels (720-663=57) witch are enough to render 3 more characters (57/17=3) in that line. In this case, you need another limitation. So you should add some padding that are calculated dynamically to control number of characters in a line.
这篇关于试图使文本控制台具有40列或字符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!