试图使文本控制台具有40列或字符 [英] trying to make a text console with 40 columns or characters

查看:75
本文介绍了试图使文本控制台具有40列或字符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在扩展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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆