最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

android閱讀器長(zhǎng)按選擇文字功能實(shí)現(xiàn)代碼

 更新時(shí)間:2017年07月06日 11:41:30   作者:楠之楓雪  
本篇文章主要介紹了android閱讀器長(zhǎng)按選擇文字功能實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,有興趣的可以了解一下

前言: 有時(shí)候我們需要實(shí)現(xiàn)長(zhǎng)按選擇文字功能,比如閱讀器一般都有這個(gè)功能,有時(shí)候某個(gè)自定義控件上可能就有這種需求,如何實(shí)現(xiàn)呢?正好最近還算閑,想完善一下自己寫(xiě)的那個(gè)輕量級(jí)的txt文件閱讀器(比如這個(gè)長(zhǎng)按選擇文字的功能就想加進(jìn)去)。于是花了兩三天時(shí)間,實(shí)現(xiàn)了這個(gè)功能,效果還是不錯(cuò)的。

首先先看看效果圖吧:

這里寫(xiě)圖片描述

授人以魚(yú)不如授人以漁,下面具體實(shí)現(xiàn)原理的教程。

1.實(shí)現(xiàn)原理

原理其實(shí)也不難,簡(jiǎn)單總結(jié)就是:繪制文字時(shí)把顯示的文字的坐標(biāo)記錄下來(lái)(記錄文字的左上右上左下右下四個(gè)點(diǎn)坐標(biāo)),作用就是為了計(jì)算滑動(dòng)范圍。執(zhí)行了長(zhǎng)按事件后,通過(guò)按的坐標(biāo),在當(dāng)前顯示的文字?jǐn)?shù)據(jù)中根據(jù)點(diǎn)的坐標(biāo)查找到按著的字,得到長(zhǎng)按后選擇的位置與文字。當(dāng)執(zhí)行滑動(dòng)選擇時(shí),根據(jù)手指滑動(dòng)的位置坐標(biāo)與當(dāng)前顯示的文字?jǐn)?shù)據(jù)匹配來(lái)確定選擇的范圍與文字。

2.具體實(shí)現(xiàn)

a.封裝

為了便于操作,首先對(duì)顯示可見(jiàn)的字符、顯示的行數(shù)據(jù)進(jìn)行封裝。

ShowChar:

public class ShowChar {//可見(jiàn)字符數(shù)據(jù)封裝

  public char chardata ;//字符數(shù)據(jù)
  public Boolean Selected =false;//當(dāng)前字符是否被選中
  public Point TopLeftPosition = null;
  public Point TopRightPosition = null;
  public Point BottomLeftPosition = null;
  public Point BottomRightPosition = null;

  public float charWidth = 0;//字符寬度
  public int Index = 0;//當(dāng)前字符位置


}

ShowLine :

public class ShowLine {//顯示的行數(shù)據(jù)
  public List<ShowChar> CharsData = null;

  /**
   *@return
   *--------------------
   *TODO 獲取該行的數(shù)據(jù)
   *--------------------
   */
  public String getLineData(){
    String linedata = "";  
    if(CharsData==null||CharsData.size()==0) return linedata;
    for(ShowChar c:CharsData){
      linedata = linedata+c.chardata;
    }
    return linedata;
  }
}

說(shuō)明:閱讀器顯示數(shù)據(jù)是一行一行的,每行都有不確定數(shù)量的字符,每個(gè)字符有自己的信息,比如字符寬度、字符在數(shù)據(jù)集合中的下標(biāo)等。繪制時(shí),通過(guò)繪制ShowLine 去繪制每行的數(shù)據(jù)。

b.數(shù)據(jù)轉(zhuǎn)化

繪制前,我們需要先要把數(shù)據(jù)轉(zhuǎn)化為上面封裝的格式數(shù)據(jù)以便我們使用。這個(gè)要怎么做?因?yàn)槲覀冃枰獙⒆址D(zhuǎn)化為一行一行的數(shù)據(jù),同時(shí)每個(gè)字符的字符寬度需要測(cè)量出來(lái)。如果對(duì)繪制比較熟悉的話,應(yīng)該會(huì)知道系統(tǒng)有個(gè)paint.measureText可以用來(lái)測(cè)量字符的寬度,這里可以借助這個(gè)來(lái)實(shí)現(xiàn)測(cè)量字符的寬度,同時(shí)轉(zhuǎn)化為我們想要行數(shù)據(jù)。

首先,寫(xiě)個(gè)方法,可以將傳入的字符串轉(zhuǎn)化為行數(shù)據(jù):

  /**
   *@param cs 
   *@param medsurewidth 行測(cè)量的最大寬度
   *@param textpadding 字符間距
   *@param paint 測(cè)量的畫(huà)筆
   *@return 如果cs為空或者長(zhǎng)度為0,返回null
   *--------------------
   *TODO 
   *--------------------
   */
  public static BreakResult BreakText(char[] cs, float medsurewidth, float textpadding, Paint paint) {  
    if(cs==null||cs.length==0){return null;}
    BreakResult breakResult = new BreakResult();    
    breakResult.showChars = new ArrayList<ShowChar>();
    float width = 0;

    for (int i = 0, size = cs.length; i < size; i++) {
      String mesasrustr = String.valueOf(cs[i]);
      float charwidth = paint.measureText(mesasrustr);

      if (width <= medsurewidth && (width + textpadding + charwidth) > medsurewidth) {
        breakResult.ChartNums = i;
        breakResult.IsFullLine = true;
        return breakResult;
      }

      ShowChar showChar = new ShowChar();
      showChar.chardata = cs[i];
      showChar.charWidth = charwidth;     
      breakResult.showChars.add(showChar);
      width += charwidth + textpadding;
    }

    breakResult.ChartNums = cs.length;
    return breakResult;
  }



public static BreakResult BreakText(String text, float medsurewidth, float textpadding, Paint paint) {
    if (TextUtils.isEmpty(text)) {
      int[] is = new int[2];
      is[0] = 0;
      is[1] = 0;
      return null;
    }
    return BreakText(text.toCharArray(), medsurewidth, textpadding, paint);

  }

說(shuō)明: BreakResult 是對(duì)測(cè)量結(jié)果的簡(jiǎn)單封裝:

public class BreakResult {

  public int ChartNums = 0;//測(cè)量了的字符數(shù)
  public Boolean IsFullLine = false;//是否滿一行了
  public List<ShowChar> showChars = null;//測(cè)量了的字符數(shù)據(jù)

  public Boolean HasData() {
    return showChars != null && showChars.size() > 0;
  }
}

完成了上面的工作后,我們可以實(shí)現(xiàn)將我們顯示的數(shù)據(jù)轉(zhuǎn)化為需要的數(shù)據(jù)了。

下面是我們測(cè)試顯示的字符串:

String TextData = "jEh話說(shuō)天下大勢(shì),分久必合,合久必分。周末七國(guó)分爭(zhēng),并入于秦。及秦滅之后,楚、漢分爭(zhēng),又并入于漢。漢朝自高祖斬白蛇而起義,一統(tǒng)天下,后來(lái)光武中興,傳至獻(xiàn)帝,遂分為三國(guó)。推其致亂之由,殆始于桓、靈二帝?;傅劢d善類(lèi),崇信宦官。及桓帝崩,靈帝即位,大將軍竇武、太傅陳蕃共相輔佐。時(shí)有宦官曹節(jié)等弄權(quán),竇武、陳蕃謀誅之,機(jī)事不密,反為所害,中涓自此愈橫"
      +

  "建寧二年四月望日,帝御溫德殿。方升座,殿角狂風(fēng)驟起。只見(jiàn)一條大青蛇,從梁上飛將下來(lái),蟠于椅上。帝驚倒,左右急救入宮,百官俱奔避。須臾,蛇不見(jiàn)了。忽然大雷大雨,加以冰雹,落到半夜方止,壞卻房屋無(wú)數(shù)。建寧四年二月,洛陽(yáng)地震;又海水泛溢,沿海居民,盡被大浪卷入海中。光和元年,雌雞化雄。六月朔,黑氣十余丈,飛入溫德殿中。秋七月,有虹現(xiàn)于玉堂;五原山岸,盡皆崩裂。種種不祥,非止一端。帝下詔問(wèn)群臣以災(zāi)異之由,議郎蔡邕上疏,以為墮雞化,乃婦寺干政之所致,言頗切直。帝覽奏嘆息,因起更衣。曹節(jié)在后竊視,悉宣告左右;遂以他事陷邕于罪,放歸田里。后張讓、趙忠、封、段、曹節(jié)、侯覽、蹇碩、程曠、夏惲、郭勝十人朋比為奸,號(hào)為“十常侍”。帝尊信張讓?zhuān)魹椤鞍⒏浮?。朝政日非,以致天下人心思亂,盜賊蜂起。";

我們需要將這段字符串轉(zhuǎn)化為行數(shù)據(jù),在初始化數(shù)據(jù)的操作,下面是初始化數(shù)據(jù)的方法initData:

List<ShowLine> mLinseData = null;

  private void initData(int viewwidth, int viewheight) {
    if (mLinseData == null) {
      //將數(shù)據(jù)轉(zhuǎn)化為行數(shù)據(jù)
      mLinseData = BreakText(viewwidth, viewheight);
    }

  }

  private List<ShowLine> BreakText(int viewwidth, int viewheight) {
    List<ShowLine> showLines = new ArrayList<ShowLine>();
    while (TextData.length() > 0) {
      BreakResult breakResult = TextBreakUtil.BreakText(TextData, viewwidth, 0, mPaint);

      if (breakResult != null && breakResult.HasData()) {
        ShowLine showLine = new ShowLine();
        showLine.CharsData = breakResult.showChars;
        showLines.add(showLine);

      } else {
        break;
      }

      TextData = TextData.substring(breakResult.ChartNums);

    }

    int index = 0;
    for (ShowLine l : showLines) {
      for (ShowChar c : l.CharsData) {
        c.Index = index++;
      }
    }
    return showLines;
  }

只要調(diào)用initData方法,我們就可以將TextData的數(shù)據(jù)轉(zhuǎn)為顯示的行數(shù)據(jù)Linedata集合mLinseData 。

值得注意的是,調(diào)用這個(gè)方法需求知道控件的長(zhǎng)寬,根據(jù)view的生命周期,我們可以在onmeasures里面調(diào)用這個(gè)方法進(jìn)行初始化。

@Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int viewwidth = getMeasuredWidth();
    int viewheight = getMeasuredHeight();
    initData(viewwidth, viewheight);
  }

數(shù)據(jù)轉(zhuǎn)化完成后,接著我們需要把數(shù)據(jù)一行一行的繪制出來(lái):

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);  

    LineYPosition = TextHeight + LinePadding;//第一行顯示的y坐標(biāo)
    for (ShowLine line : mLinseData) {
      DrawLineText(line, canvas);//繪制每一行,并記錄每個(gè)字符的坐標(biāo)
    }
  }

DrawLineText方法:

private void DrawLineText(ShowLine line, Canvas canvas) {
    canvas.drawText(line.getLineData(), 0, LineYPosition, mPaint);

    float leftposition = 0;
    float rightposition = 0;
    float bottomposition = LineYPosition + mPaint.getFontMetrics().descent;

    for (ShowChar c : line.CharsData) {
      rightposition = leftposition + c.charWidth;
      Point tlp = new Point();
      c.TopLeftPosition = tlp;
      tlp.x = (int) leftposition;
      tlp.y = (int) (bottomposition - TextHeight);

      Point blp = new Point();
      c.BottomLeftPosition = blp;
      blp.x = (int) leftposition;
      blp.y = (int) bottomposition;

      Point trp = new Point();
      c.TopRightPosition = trp;
      trp.x = (int) rightposition;
      trp.y = (int) (bottomposition - TextHeight);

      Point brp = new Point();
      c.BottomRightPosition = brp;
      brp.x = (int) rightposition;
      brp.y = (int) bottomposition;
      leftposition = rightposition;

    }
    LineYPosition = LineYPosition + TextHeight + LinePadding;
  }

運(yùn)行一下,目前顯示效果如下:

這里寫(xiě)圖片描述

實(shí)現(xiàn)這些后,接下來(lái)需要實(shí)現(xiàn)長(zhǎng)按選擇功能以及滑動(dòng)選擇文字功能。如何實(shí)現(xiàn)長(zhǎng)按呢,自己寫(xiě)肯定可以,只是也太麻煩了,所以我們這里借助系統(tǒng)提供的長(zhǎng)按事件就可以。我實(shí)現(xiàn)的思路是這樣的,首先先將事件處理模式分四種:

private enum Mode {

    Normal, //正常模式
    PressSelectText,//長(zhǎng)按選中文字
    SelectMoveForward, //向前滑動(dòng)選中文字
    SelectMoveBack//向后滑動(dòng)選中文字
  }

在沒(méi)有做任何處理情況下是Normal模式,如果手勢(shì)發(fā)生了,Down事件觸發(fā),記錄當(dāng)前Down的坐標(biāo),如果用戶一直按著,必然觸發(fā)長(zhǎng)按事件,模式轉(zhuǎn)化為PressSelectText,通過(guò)記錄的Down的坐標(biāo),去數(shù)據(jù)集合中找到當(dāng)前長(zhǎng)按的字符,繪畫(huà)出選擇的文字的背景。

思路是這樣,那么就干吧。首先注冊(cè)長(zhǎng)按事件,在初始化使注冊(cè)該事件。

private void init() {
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setTextSize(29);

    mTextSelectPaint = new Paint();
    mTextSelectPaint.setAntiAlias(true);
    mTextSelectPaint.setTextSize(19);
    mTextSelectPaint.setColor(TextSelectColor);

    mBorderPointPaint = new Paint();
    mBorderPointPaint.setAntiAlias(true);
    mBorderPointPaint.setTextSize(19);
    mBorderPointPaint.setColor(BorderPointColor);

    FontMetrics fontMetrics = mPaint.getFontMetrics();
    TextHeight = Math.abs(fontMetrics.ascent) + Math.abs(fontMetrics.descent);

    setOnLongClickListener(mLongClickListener);

  }
private OnLongClickListener mLongClickListener = new OnLongClickListener() {

    @Override
    public boolean onLongClick(View v) {

      if (mCurrentMode == Mode.Normal) {
        if (Down_X > 0 && Down_Y > 0) {// 說(shuō)明還沒(méi)釋放,是長(zhǎng)按事件
          mCurrentMode = Mode.PressSelectText;
          postInvalidate();//刷新
        }
      }
      return false;
    }
  };

這里 Down_X , Down_Y ; 初始化值都是-1,如果執(zhí)行了down事件后它們肯定大于0,如果執(zhí)行了Action_up事件,釋放設(shè)置值為-1,只是為了判斷使用而已。

然后onDraw中需要判斷一下并繪制選擇的文字了。

@Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    LineYPosition = TextHeight + LinePadding;//第一行的y坐標(biāo)
    for (ShowLine line : mLinseData) {
      DrawLineText(line, canvas);//繪制每一
    }

    if (mCurrentMode != Mode.Normal) {
      DrawSelectText(canvas);//如果不是正常的話,繪制選擇
    }
  }
private void DrawSelectText(Canvas canvas) {
    if (mCurrentMode == Mode.PressSelectText) {
      DrawPressSelectText(canvas);//繪制長(zhǎng)按選擇的字符
    } else if (mCurrentMode == Mode.SelectMoveForward) {//向前滑動(dòng)選擇
      DrawMoveSelectText(canvas);//繪制滑動(dòng)時(shí)選擇的文字背景
    } else if (mCurrentMode == Mode.SelectMoveBack) {//向后滑動(dòng)選擇
      DrawMoveSelectText(canvas);//繪制滑動(dòng)時(shí)選擇的文字背景
    }
  }

這時(shí)如果執(zhí)行了長(zhǎng)按事件,mCurrentMode == Mode.PressSelectText,將執(zhí)行繪制長(zhǎng)按選擇的字符。

     //繪制長(zhǎng)按選中的數(shù)據(jù)
private void DrawPressSelectText(Canvas canvas) {
    //根據(jù)按的坐標(biāo)檢測(cè)找到長(zhǎng)按的字符
    ShowChar p = DetectPressShowChar(Down_X, Down_Y);

    if (p != null) {// 找到了選擇的字符
      FirstSelectShowChar = LastSelectShowChar = p;
      mSelectTextPath.reset();
      mSelectTextPath.moveTo(p.TopLeftPosition.x, p.TopLeftPosition.y);
      mSelectTextPath.lineTo(p.TopRightPosition.x, p.TopRightPosition.y);
      mSelectTextPath.lineTo(p.BottomRightPosition.x, p.BottomRightPosition.y);
      mSelectTextPath.lineTo(p.BottomLeftPosition.x, p.BottomLeftPosition.y);
      //繪制文字背景
      canvas.drawPath(mSelectTextPath, mTextSelectPaint);
      //繪制邊界的線與指示塊
      DrawBorderPoint(canvas);

    }
  }

檢測(cè)點(diǎn)擊點(diǎn)所在的字符方法:

  /**
   *@param down_X2
   *@param down_Y2
   *@return
   *--------------------
   *TODO 檢測(cè)獲取按壓坐標(biāo)所在位置的字符,沒(méi)有的話返回null
   *--------------------
   */
  private ShowChar DetectPressShowChar(float down_X2, float down_Y2) {

    for (ShowLine l : mLinseData) {
      for (ShowChar c : l.CharsData) {
        if (down_Y2 > c.BottomLeftPosition.y) {
          break;// 說(shuō)明是在下一行
        }
        if (down_X2 >= c.BottomLeftPosition.x && down_X2 <= c.BottomRightPosition.x) {
          return c;
        }

      }
    }

    return null;
  }

基本上長(zhǎng)按事件操作都完成了,我們運(yùn)行長(zhǎng)按文字看看效果:

繪制了長(zhǎng)按選擇的字符后,我們需要實(shí)現(xiàn)按著左右的指示塊進(jìn)行左右或者上下滑動(dòng)去選擇文字。為了便于操作,向上滑動(dòng)與向下滑動(dòng)都有限制滑動(dòng)范圍,如下圖:

這里寫(xiě)圖片描述

藍(lán)色的區(qū)域是手指按著后觸發(fā)允許滑動(dòng)。按著左邊的小藍(lán)色區(qū)域,mCurrentMode == Mode.SelectMoveForward,允許向上滑動(dòng)選擇文字,就是手指滑動(dòng)坐標(biāo)滑動(dòng)到黃色區(qū)域有效。按著右邊的小藍(lán)色區(qū)域,mCurrentMode == Mode.SelectMoveBack,允許向下滑動(dòng)選擇文字,就是手指滑動(dòng)到綠色區(qū)域有效。

選擇時(shí),我們只會(huì)記錄兩個(gè)字符,就是選擇的文字的開(kāi)始字符與結(jié)束字符:

private ShowChar FirstSelectShowChar = null;
private ShowChar LastSelectShowChar = null;

注意的是當(dāng)長(zhǎng)按選擇一個(gè)字符后:FirstSelectShowChar = LastSelectShowChar;

所以整個(gè)過(guò)程是:滑動(dòng)時(shí),如果按著左邊的藍(lán)色區(qū)域,將允許向前滑動(dòng),這時(shí)mCurrentMode == Mode.SelectMoveForward,向前滑動(dòng)即在黃色區(qū)域滑動(dòng),這時(shí)就可以根據(jù)手指滑動(dòng)坐標(biāo)找到滑動(dòng)后的FirstSelectShowChar ,然后刷新界面。向下滑動(dòng)同理。

下面是代碼實(shí)現(xiàn):

先在Action_Down里判斷是向下滑動(dòng)還是向下滑動(dòng),如果都不是,重置,使長(zhǎng)按選擇的文字恢復(fù)原樣。

case MotionEvent.ACTION_DOWN:
      Down_X = Tounch_X;
      Down_Y = Tounch_Y;

      if (mCurrentMode != Mode.Normal) {
        Boolean isTrySelectMove = CheckIfTrySelectMove(Down_X, Down_Y);

        if (!isTrySelectMove) {// 如果不是準(zhǔn)備滑動(dòng)選擇文字,轉(zhuǎn)變?yōu)檎DJ?,隱藏選擇框
          mCurrentMode = Mode.Normal;
          invalidate();
        }
      }

      break;

在滑動(dòng)時(shí)判斷,如果是向上滑動(dòng),檢測(cè)獲取當(dāng)前滑動(dòng)時(shí)的FirstSelectShowChar ;如果是向下滑動(dòng),檢測(cè)獲取當(dāng)前滑動(dòng)時(shí)的LastSelectShowChar ,然后刷新界面。

case MotionEvent.ACTION_MOVE:
      if (mCurrentMode == Mode.SelectMoveForward) {
        if (CanMoveForward(event.getX(), event.getY())) {// 判斷是否是向上移動(dòng)
          ShowChar firstselectchar = DetectPressShowChar(event.getX(), event.getY());//獲取當(dāng)前滑動(dòng)坐標(biāo)的下的字符
          if (firstselectchar != null) {
            FirstSelectShowChar = firstselectchar;
            invalidate();
          } 

        }

      } else if (mCurrentMode == Mode.SelectMoveBack) {

        if (CanMoveBack(event.getX(), event.getY())) {// 判斷是否可以向下移動(dòng)         
          ShowChar lastselectchar = DetectPressShowChar(event.getX(), event.getY());//獲取當(dāng)前滑動(dòng)坐標(biāo)的下的字符
          if (lastselectchar != null) {
            LastSelectShowChar = lastselectchar;
            invalidate();
          } 

        } 
      }

      break;

判斷是否向上滑動(dòng)方法:

private boolean CanMoveForward(float Tounchx, float Tounchy) {

    Path p = new Path();
    p.moveTo(LastSelectShowChar.TopRightPosition.x, LastSelectShowChar.TopRightPosition.y);
    p.lineTo(getWidth(), LastSelectShowChar.TopRightPosition.y);
    p.lineTo(getWidth(), 0);
    p.lineTo(0, 0);
    p.lineTo(0, LastSelectShowChar.BottomRightPosition.y);
    p.lineTo(LastSelectShowChar.BottomRightPosition.x, LastSelectShowChar.BottomRightPosition.y);
    p.lineTo(LastSelectShowChar.TopRightPosition.x, LastSelectShowChar.TopRightPosition.y);

    return computeRegion(p).contains((int) Tounchx, (int) Tounchy);
  }

判斷是否向下滑動(dòng):

private boolean CanMoveBack(float Tounchx, float Tounchy) {

    Path p = new Path();
    p.moveTo(FirstSelectShowChar.TopLeftPosition.x, FirstSelectShowChar.TopLeftPosition.y);
    p.lineTo(getWidth(), FirstSelectShowChar.TopLeftPosition.y);
    p.lineTo(getWidth(), getHeight());
    p.lineTo(0, getHeight());
    p.lineTo(0, FirstSelectShowChar.BottomLeftPosition.y);
    p.lineTo(FirstSelectShowChar.BottomLeftPosition.x, FirstSelectShowChar.BottomLeftPosition.y);
    p.lineTo(FirstSelectShowChar.TopLeftPosition.x, FirstSelectShowChar.TopLeftPosition.y);

    return computeRegion(p).contains((int) Tounchx, (int) Tounchy);
  }


private Region computeRegion(Path path) {
    Region region = new Region();
    RectF f = new RectF();
    path.computeBounds(f, true);
    region.setPath(path, new Region((int) f.left, (int) f.top, (int) f.right, (int) f.bottom));
    return region;
  }

手勢(shì)操作處理完成了,剩下的就是在ondraw時(shí)判斷到mCurrentMode == Mode.SelectMoveForward或者mCurrentMode == Mode.SelectMoveBack繪制出選擇的范圍背景。

private void DrawSelectText(Canvas canvas) {
    if (mCurrentMode == Mode.PressSelectText) {
      DrawPressSelectText(canvas);//繪制長(zhǎng)按選擇的字符
    } else if (mCurrentMode == Mode.SelectMoveForward) {//向前滑動(dòng)選擇
      DrawMoveSelectText(canvas);//繪制滑動(dòng)時(shí)選擇的文字背景
    } else if (mCurrentMode == Mode.SelectMoveBack) {//向后滑動(dòng)選擇
      DrawMoveSelectText(canvas);//繪制滑動(dòng)時(shí)選擇的文字背景
    }
  }

private void DrawMoveSelectText(Canvas canvas) {
    if (FirstSelectShowChar == null || LastSelectShowChar == null)     return;
    GetSelectData();//獲取選擇字符的數(shù)據(jù),轉(zhuǎn)化為選擇的行數(shù)據(jù)
    DrawSeletLines(canvas);//繪制選擇的行數(shù)據(jù)
    DrawBorderPoint(canvas);//繪制出邊界的方塊或圓點(diǎn)
  }

private void DrawSeletLines(Canvas canvas) 
    DrawOaleSeletLinesBg(canvas);
  }

  private void DrawOaleSeletLinesBg(Canvas canvas) {// 繪制橢圓型的選中背景
    for (ShowLine l : mSelectLines) {      
      if (l.CharsData != null && l.CharsData.size() > 0) {        
        ShowChar fistchar = l.CharsData.get(0);
        ShowChar lastchar = l.CharsData.get(l.CharsData.size() - 1);

        float fw = fistchar.charWidth;
        float lw = lastchar.charWidth;

        RectF rect = new RectF(fistchar.TopLeftPosition.x, fistchar.TopLeftPosition.y,
            lastchar.TopRightPosition.x, lastchar.BottomRightPosition.y);

        canvas.drawRoundRect(rect, fw / 2,
             TextHeight / 2, mTextSelectPaint);

      }
    }
  }

基本完成了,運(yùn)行一下,效果還是不錯(cuò)的。

這里寫(xiě)圖片描述

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android 虛擬按鍵與沉浸式的適配方法

    Android 虛擬按鍵與沉浸式的適配方法

    今天小編就為大家分享一篇Android 虛擬按鍵與沉浸式的適配方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • Android-如何將RGB彩色圖轉(zhuǎn)換為灰度圖方法介紹

    Android-如何將RGB彩色圖轉(zhuǎn)換為灰度圖方法介紹

    本文將詳細(xì)介紹Android-如何將RGB彩色圖轉(zhuǎn)換為灰度圖方法,需要了解更多的朋友可以參考下
    2012-11-11
  • Android日歷控件的實(shí)現(xiàn)方法

    Android日歷控件的實(shí)現(xiàn)方法

    這篇文章主要為大家詳細(xì)介紹了Android如何打造自己的日歷控件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • android通過(guò)拼音搜索中文的功能實(shí)現(xiàn)代碼

    android通過(guò)拼音搜索中文的功能實(shí)現(xiàn)代碼

    這篇文章主要介紹了android通過(guò)拼音搜索中文的功能實(shí)現(xiàn)代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Android中Service的全面總結(jié)

    Android中Service的全面總結(jié)

    這篇文章主要全面總結(jié)了Android中Service的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • Android AsyncTask用法巧用實(shí)例代碼

    Android AsyncTask用法巧用實(shí)例代碼

    這篇文章主要介紹了Android AsyncTask用法巧用實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • android 6.0 權(quán)限授權(quán)方法

    android 6.0 權(quán)限授權(quán)方法

    今天小編就為大家分享一篇android 6.0 權(quán)限授權(quán)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • Android 鍵盤(pán)開(kāi)發(fā)知識(shí)點(diǎn)總結(jié)

    Android 鍵盤(pán)開(kāi)發(fā)知識(shí)點(diǎn)總結(jié)

    這篇文章我們給大家總結(jié)了Android 鍵盤(pán)開(kāi)發(fā)的相關(guān)知識(shí)點(diǎn)內(nèi)容以及開(kāi)發(fā)心得,有需要的朋友參考學(xué)習(xí)下。
    2018-06-06
  • android 屏幕亮度調(diào)節(jié)方法詳解

    android 屏幕亮度調(diào)節(jié)方法詳解

    分析一下自動(dòng)調(diào)節(jié)屏幕亮度手機(jī)隨著光線的強(qiáng)度自我調(diào)節(jié),也就是在亮的光線下屏幕自動(dòng)亮一些,暗的時(shí)候就自動(dòng)調(diào)暗一些,本文將詳細(xì)介紹android 屏幕亮度調(diào)節(jié)
    2012-11-11
  • Android ActivityManagerService啟動(dòng)流程詳解

    Android ActivityManagerService啟動(dòng)流程詳解

    這篇文章主要介紹了Android ActivityManagerService啟動(dòng)流程,AMS,即ActivityManagerService,是安卓java framework的一個(gè)服務(wù),運(yùn)行在system_server進(jìn)程。此服務(wù)十分重要,因?yàn)樗芾碇沧康乃拇蠼M件,是安卓APP開(kāi)發(fā)者最常接觸到的一個(gè)服務(wù)
    2023-02-02

最新評(píng)論

江陵县| 县级市| 江陵县| 安乡县| 工布江达县| 都昌县| 崇州市| 邮箱| 沂南县| 沙湾县| 沙湾县| 辰溪县| 沂南县| 泽普县| 新建县| 罗定市| 郴州市| 罗甸县| 平度市| 岳池县| 阳原县| 富锦市| 武汉市| 靖江市| 荆州市| 长治县| 商水县| 晋城| 阿拉尔市| 界首市| 含山县| 永清县| 呼和浩特市| 武平县| 泰宁县| 鞍山市| 维西| 类乌齐县| 新闻| 抚宁县| 清水县|