Android畫板開發(fā)之添加文本文字

一、前言

創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供巴州網(wǎng)站建設(shè)、巴州做網(wǎng)站、巴州網(wǎng)站設(shè)計(jì)、巴州網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、巴州企業(yè)網(wǎng)站模板建站服務(wù),十余年巴州做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。

添加文本,也是屬于 一個(gè)比較簡(jiǎn)單的功能,在第二篇的時(shí)候,添加了橡皮擦,在橡皮擦里面通過一個(gè)模式的形式進(jìn)行畫筆的判斷,當(dāng)然文本也是如此,添加一個(gè)文本模式,在onTouchDown的時(shí)候,彈出PopupWindow,輸入文本,然后PopupWindow消失的時(shí)候,利用staticLayout繪制到畫布上即可。當(dāng)然也有些需要注意的地方

Android畫板開發(fā)之添加文本文字

下面一步步來實(shí)現(xiàn)

二、實(shí)現(xiàn)

2.1 添加文本模式

例如橡皮擦那樣,添加多一個(gè)文本模式,然后setModel的時(shí)候,需要把畫筆的樣式修改為FILL,如果是STROKE進(jìn)行文字繪制會(huì)變成空心文字。

companion object {
    const val EDIT_MODE_PEN = 0x1L    //畫筆模式
    const val EDIT_MODE_ERASER = 0x2L  //橡皮擦模式
    const val EDIT_MODE_TEXT = 0x3L  //文字模式

  }

  @Retention(AnnotationRetention.SOURCE)
  @IntDef(EDIT_MODE_PEN, EDIT_MODE_ERASER, EDIT_MODE_TEXT)
  annotation class EditMode

  /**
   * 設(shè)置畫筆模式
   */
  fun setModel(@EditMode model: Long) {
    mMode = model
    when (model) {
      EDIT_MODE_PEN -> {
        //畫線
        mPaint.xfermode = null
        mPaint.style = Paint.Style.STROKE
      }
      EDIT_MODE_ERASER -> {
        mPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)

      }
      EDIT_MODE_TEXT -> {
        mPaint.style = Paint.Style.FILL
      }
    }
  }

2.2 修改bean類型

StaticLayout 是一個(gè)為不可編輯的文本布局的類,這意味著一旦布局完成,文本內(nèi)容就不可以改變。在單純地使用TextView來展示靜態(tài)文本的時(shí)候,創(chuàng)建的就是 StaticLayout,在api25,Textview源碼6858行可以看到。

StaticLayout.Builder builder = StaticLayout.Builder.obtain(mHint, 0,
     mHint.length(), mTextPaint, hintWidth)
     .setAlignment(alignment)
     .setTextDirection(mTextDir)
     .setLineSpacing(mSpacingAdd, mSpacingMult)
     .setIncludePad(mIncludePad)
     .setBreakStrategy(mBreakStrategy)
     .setHyphenationFrequency(mHyphenationFrequency);

我們畫板的繪制文字也是用到了這個(gè)StaticLayout,它有三個(gè)構(gòu)造方法,我們用最少那個(gè)即可:

public StaticLayout(CharSequence source, //字符串
   TextPaint paint, //畫筆對(duì)象
   int width,  //layout的寬度,字符串超出寬度時(shí)自動(dòng)換行。
   Layout.Alignment align, //layout的對(duì)其方式,有ALIGN_CENTER, ALIGN_NORMAL, ALIGN_OPPOSITE 三種。
   float spacingmult,  //相對(duì)行間距,相對(duì)字體大小,1.5f表示行間距為1.5倍的字體高度。
   float spacingadd,  //在基礎(chǔ)行距上添加多少
   boolean includepad)  //文本頂部和底部是否留白

所以,bean類在之前的基礎(chǔ)上,添加了文本、寬度、xy軸的偏移,然后繪制的時(shí)候,利用staticLayout進(jìn)行了繪制。

data class PaintBean(
    var mPaint: Paint,  //保存畫筆
    var mPath: Path?,     //保存路徑
    var mText: String,    //文本
    var mWidth: Int,
    var mOffX: Float,
    var mOffY: Float,
    private @TPTextView.EditMode var mMode:Long
) {

  constructor(mPaint: Paint, mPath: Path) : this(mPaint,mPath,"",0,0f,0f,TPTextView.EDIT_MODE_PEN)

  /**
   * 撤銷和反撤銷之后 重新繪制
   * @param canvas 繪制的畫布
   */
  fun draw(canvas: Canvas){

    when(mMode){

      TPTextView.EDIT_MODE_TEXT -> {

        if(!TextUtils.isEmpty(mText)){
          //調(diào)節(jié)畫布起始坐標(biāo)進(jìn)行繪制
          canvas.translate(mOffX,mOffY)
          //利用staticLayout生成文字,不然不能換行
          val staticLayout = StaticLayout(mText,mPaint as TextPaint,mWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false)
          staticLayout.draw(canvas)
          //Log.e("@@","長(zhǎng)度:"+staticLayout.width)
          //canvas.drawText(mText,mTextOffX,mTextOffY,mPaint)
          //恢復(fù)畫布坐標(biāo)
          canvas.translate(-mOffX,-mOffY)

        }

      }
      else -> {
        canvas.drawPath(mPath,mPaint)
      }

    }

  }

  fun getMode():Long = mMode

}

2.3 彈窗處理

接下來,設(shè)置一個(gè)彈框PopupWindow進(jìn)行文本的輸入,彈窗里面的控件就是一個(gè)EditText。 在彈窗消失的時(shí)候添加到畫筆列表,然后進(jìn)行重繪。 在這里有三點(diǎn)注意點(diǎn)

  • 軟鍵盤自動(dòng)彈出
  • 編輯框顯示在軟鍵盤上面
  • 彈框顯示的位置
  • 右邊越界
private var mTextPopup: PopupWindow? = null
private var mTextView: EditText? = null

  /**
   * 顯示popup文本輸入彈窗
   */
  private fun showTextPopup() {

    if (null == mTextPopup) {
      mTextView = EditText(context)
      mTextView?.hint = "文字"

      mTextPopup = PopupWindow(mTextView,
          WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT,
          true)
      mTextPopup?.setOnDismissListener {
        if (!TextUtils.isEmpty(mTextView?.text)) {
          //添加到列表
          mPaintedList.add(
              PaintBean(TextPaint(mPaint), null, mTextView?.text.toString(), (width - preX).toInt(),preX,preY - mTextView!!.height / 2, EDIT_MODE_TEXT))

          invalidate()
        }
      }
      //讓popup顯示在軟鍵盤上面
      mTextPopup?.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
    }

    mTextView?.requestFocus()

    //自動(dòng)彈出軟鍵盤,會(huì)導(dǎo)致布局變化,重測(cè)量、繪制
    val imm = context.getSystemService(Service.INPUT_METHOD_SERVICE) as InputMethodManager
    imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS)


    mTextPopup?.showAtLocation(this, Gravity.TOP and Gravity.LEFT, preX.toInt(), preY.toInt()+mTextView!!.height)

  }

在觸摸的時(shí)候,進(jìn)行顯示。 移動(dòng)的時(shí)候不用操作,手指起來的時(shí)候也不用操作

@SuppressLint("ClickableViewAccessibility")
  override fun onTouchEvent(event: MotionEvent): Boolean {

    when (event.action) {
      MotionEvent.ACTION_DOWN -> { //手指按下的時(shí)候
        //記錄上次觸摸的坐標(biāo),注意ACTION_DOWN方法只會(huì)執(zhí)行一次
        preX = event.x
        preY = event.y
        when (mMode) {

          EDIT_MODE_TEXT -> {
            //彈出popupWidnwo輸入text
            showTextPopup()
            //文字在隱藏的時(shí)候添加到list
          }
          else -> {
            //將起始點(diǎn)移動(dòng)到當(dāng)前坐標(biāo)
            mPath.moveTo(event.x, event.y)
            mPaintedList.add(PaintBean(Paint(mPaint), Path(mPath)))
          }
        }

      }
      MotionEvent.ACTION_MOVE -> { //手指移動(dòng)的時(shí)候
        when (mMode) {
          EDIT_MODE_TEXT -> {

          }
          else -> {
            //繪制圓滑曲線,即貝塞爾曲線,貝塞爾曲線這個(gè)知識(shí)自行了解
            mPaintedList.get(mPaintedList.size - 1).mPath?.quadTo(preX, preY, event.x, event.y)
            preX = event.x
            preY = event.y
            //重新繪制,會(huì)調(diào)用onDraw方法
            invalidate()
          }

        }
      }
      MotionEvent.ACTION_UP -> {}
    }

    return true
  }

因?yàn)槔L制在bean類里面,所以view的onDraw方法還是以前那樣,不需要變化:

@SuppressLint("DrawAllocation")
  override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)

    //超出緩存的就固化到緩存bitmap
    while (mPaintedList.size > PAINT_RECORED_NUM) {
      val paint = mPaintedList.removeAt(0)
      paint.draw(mHoldCanvas!!)
    }

    //繪制固化的內(nèi)容到緩存Canvas
    mBufferCanvas?.drawBitmap(mHoldBitmap, 0f, 0f, null)

    //繪制記錄的畫筆
    for (paint in mPaintedList) {
      paint.draw(mBufferCanvas!!)
    }

    //畫出緩存bitmap的內(nèi)容
    canvas.drawBitmap(mBufferBitmap, 0f, 0f, null)

  }

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。

當(dāng)前文章:Android畫板開發(fā)之添加文本文字
文章出自:http://muchs.cn/article4/ishdoe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營銷面包屑導(dǎo)航、小程序開發(fā)、網(wǎng)站收錄、網(wǎng)站內(nèi)鏈網(wǎng)站改版

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

綿陽服務(wù)器托管