亚洲免费av电影一区二区三区,日韩爱爱视频,51精品视频一区二区三区,91视频爱爱,日韩欧美在线播放视频,中文字幕少妇AV,亚洲电影中文字幕,久久久久亚洲av成人网址,久久综合视频网站,国产在线不卡免费播放

        ?

        一種擴(kuò)展的Android文本顯示控件實(shí)現(xiàn)

        2015-03-02 12:03:19朱明東
        軟件導(dǎo)刊 2015年1期

        摘要:Android自帶的文本顯示控件TextView往往難以滿足排版要求。以兩端對齊排版要求為例,實(shí)現(xiàn)能夠兩端對齊的文本顯示控件ExTextView,為擴(kuò)展TextView功能提供了方法和思路。

        關(guān)鍵詞:Android;文本顯示;控件TextView;ExTextView

        DOIDOI:10.11907/rjdk.143658

        中圖分類號:TP301

        文獻(xiàn)標(biāo)識碼:A 文章編號文章

        編號:16727800(2015)001003303

        基金項(xiàng)目基金項(xiàng)目:

        作者簡介作者簡介:朱明東(1975-),男,碩士,國防信息學(xué)院一系講師,研究方向?yàn)閿?shù)據(jù)處理、數(shù)據(jù)分析、數(shù)據(jù)管理。

        0 引言

        TextView控件在Android開發(fā)中應(yīng)用比較廣泛,只要有文本顯示要求時(shí),通常都會用到它。但是TexwView控件并不十分完美,它在顯示文本時(shí),特別是有中西文混合文本時(shí),往往顯得參差不齊、不夠工整,影響了排版效果,不能滿足“兩端對齊”這一中文顯示的基本要求。Android實(shí)現(xiàn)文本兩端對齊顯示的基本方法有3種:①將文本轉(zhuǎn)換為html格式,用WebView控件顯示;②棄用TexwView控件,重新實(shí)現(xiàn)一個(gè)具有兩端對齊功能的新控件;③在TexwView控件的基礎(chǔ)上,擴(kuò)展實(shí)現(xiàn)兩端對齊功能。第一種方法需要在文本顯示前把文本轉(zhuǎn)換為html格式,這需要程序員對html格式相當(dāng)熟悉;第二種方法是重新實(shí)現(xiàn)一個(gè)文本顯示控件,需要對Android控件的實(shí)現(xiàn)機(jī)理有深入研究[1],對程序員的能力要求比較高;第三種方法相對簡單,只需在現(xiàn)有控件的基礎(chǔ)上,覆蓋文本輸出方法。本文采用第三種方法,即擴(kuò)展TextView控件功能。

        1 TextView控件機(jī)理

        要擴(kuò)展TextView控件功能,首先要對TextView控件的實(shí)現(xiàn)機(jī)理有一定了解。Android的每一個(gè)控件雖然實(shí)現(xiàn)起來相當(dāng)復(fù)雜,但除了具體實(shí)現(xiàn)細(xì)節(jié)外,幾乎所有的可視控件都包含兩個(gè)要素:一個(gè)是與用戶的交互界面(UI),另一個(gè)是與用戶交互的用戶輸入事件。TextView作為Android的一個(gè)基礎(chǔ)控件也不例外,用戶界面是通過在畫布上繪制UI,用戶主要是鍵盤輸入以及觸摸屏輸入。因此,分析TextView控件的機(jī)理就是要搞清控件界面的繪制框架及其輸入過程。本文主要關(guān)注TextView控件的界面繪制步驟。控件的UI繪制操作通常分為3步,分別是測量、布局和繪制。

        1.1 測量

        對于一個(gè)可視控件,必須確定其所占空間的大小,所以TextView要重寫父類View的成員函數(shù)onMeasure。該函數(shù)有兩個(gè)參數(shù),分別是用來描述寬度測量規(guī)范的widthMeasureSpec和高度測量規(guī)范的heightMeasureSpec。測量規(guī)范使用1個(gè)int值來表示,這個(gè)int值包含了2個(gè)分量。第1個(gè)是mode分量,使用最高2位來表示。測量模式有3種,分別是MeasureSpec.UNSPECIFIED(0)、MeasureSpec.EXACTLY(1)和MeasureSpec.AT_MOST(2);第2個(gè)是size分量,使用低30位來表示。當(dāng)mode分量等于MeasureSpec.EXACTLY時(shí),size分量的值就是父視圖設(shè)置的寬度或者高度;當(dāng)mode分量等于MeasureSpec.AT_MOST時(shí),size分量的值就是父視圖限定當(dāng)前控件設(shè)置的最大寬度或者高度;當(dāng)mode分量等于MeasureSpec.UNSPECIFIED時(shí),父視圖不限定當(dāng)前控件所設(shè)置的寬度或者高度,這時(shí)候當(dāng)前控件就按照實(shí)際需求來設(shè)置寬度和高度。

        1.2 布局

        通過測量后確定了控件的大小,但是控件的位置還未確定??丶奈恢檬峭ㄟ^布局這個(gè)操作來完成的。Android可視控件是按照樹形結(jié)構(gòu)組織在一起的,其中,子控件的位置由父控件來設(shè)置,也就是說,只有容器類控件才執(zhí)行布局操作,通過重寫父類View的成員函數(shù)onLayout來實(shí)現(xiàn)。由于TextView控件不是容器類控件,因此,它可以不重寫父類View的成員函數(shù)onLayout。

        1.3 繪制

        經(jīng)過測量和布局操作后,就確定了控件TextView的大小和位置,接下來繪制UI??丶榱死L制UI,必須重寫父類View的成員函數(shù)onDraw。該函數(shù)只有一個(gè)參數(shù)canvas,canvas描述的是一塊畫布,控件的UI就是繪制在這塊畫布上的。畫布提供了豐富的接口來繪制UI,例如畫線(drawLine)、畫圓(drawCircle)、輸出文字(drawText)和貼圖(drawBitmap)等等。有了這些UI畫圖接口之后,就可以隨心所欲地繪制控件的UI了。

        通過分析TextView控件的機(jī)理,不難發(fā)現(xiàn),TextView對文本的顯示是通過在畫布(canvas)上輸出文本實(shí)現(xiàn)的。因此要在TextView的基礎(chǔ)上實(shí)現(xiàn)文本的兩端對齊,關(guān)鍵是要重新安排每一行的字符數(shù),控制字間距,在TextView的畫布(canvas)上精確地輸出每一個(gè)字符,從而確保每一行的第一個(gè)字符和最后一個(gè)字符是對齊的。

        2 擴(kuò)展TextView設(shè)計(jì)

        2.1 兩端對齊顯示的基本要求

        要實(shí)現(xiàn)文本的兩端對齊,表面上是每行的最后一個(gè)字符在縱坐標(biāo)上保持一致,其實(shí)還要考慮文本在顯示格式上的要求,特別是每一行的第一個(gè)字符(行首)和最后一個(gè)字符(行尾)是否符合格式規(guī)范。需要考慮的格式規(guī)范要求有:①行首字符不能是以下字符:句號(。.)、問號(??)、嘆號(?。。?、逗號(,,)、冒號(::)和分號(;;)和引號(””)、括號())]})、書名號(》>)的后一半等;②行尾字符不能是以下字符:引號(“”)、括號((([{)、書名號(《<)的前一半。

        2.2 ExTextView設(shè)計(jì)[2]

        ExTextView繼承了Android的TextView,其繼承關(guān)系如圖1所示,ExTextView的類圖如圖2所示。

        ExTextView主要的屬性包括文本高度(m_iTextHeight)、文本寬度(m_iTextWidth)、畫筆(mPaint)、文本(text)、行間距(LineSpace)、左邊距(left_Margin)、右邊距(right_Margin)、上邊距(top_Margin)、下邊距(bottom_Margin)、字體高度(m_iFontHeight)、所有行屬性(strings)。

        其中,描述行屬性的內(nèi)部類Tlineattr包含3個(gè)成員,分別是該行所包含的字符串(linetext)、該行的字間距(extrawidth)和該行每一個(gè)字符的輸出寬度(widths)。

        ExTextView的機(jī)理是:確定每一行字符屬性的IniLines()方法和覆蓋父類的OnDraw()方法。IniLines()方法主要是確定第一行所包含的字符,保證行首字符和行尾字符符合格式規(guī)范的要求,其判斷邏輯如圖3所示。OnDraw()方法主要是根據(jù)每一行所包含的字符,確定字間距,保證所有行首字符的水平坐標(biāo)值一致,所有行尾字符的水平坐標(biāo)值一致,操作流程如圖4所示。

        3 擴(kuò)展TextView實(shí)現(xiàn)

        3.1 主要代碼

        ExTextView要能夠?qū)崿F(xiàn)兩端對齊,其核心是先要分配每一行的字符,然后重寫父類的成員函數(shù)onDraw ()。

        分配字符的方法IniLines()實(shí)現(xiàn)如下:

        private void IniLines() {

        strings.clear();

        String Text = text;//得到要輸出的文本

        intm_LineWidth = m_iTextWidth - left_Margin - right_Margin; //可輸出的畫布寬度

        float[] widths = new float[Text.length()]; //保存每個(gè)字符所占寬度的數(shù)組

        mPaint.getTextWidths(Text, widths); //得到每個(gè)字符輸出時(shí)的寬度

        final String Laststr = "((《“{[<"; //不能是行尾的字符

        final String Firststr = "、,。;:)?”,.;:)》?/-]}>"; //不能是行首的字符

        float curwidth = 0; //保存當(dāng)前行所含字符的總的寬度

        intstartindex = 0; //行開始的字符位置

        intendindex = 0; //行結(jié)束的字符位置

        String lastch = ""; //上一個(gè)字符

        Boolean IsCalExtraWidth = false;//是否需要計(jì)算字間距

        for (inti = 0; i

        Boolean lineclosed = false; //當(dāng)前行是否結(jié)束

        String ch = Text.substring(i, i + 1); //得到當(dāng)前字符

        curwidth = curwidth + widths[i]; //當(dāng)前行已輸出字符的寬度

        if (curwidth>m_LineWidth) { //超出了行寬

        lineclosed = true;//當(dāng)前行結(jié)束

        IsCalExtraWidth = true;//需要計(jì)算字間距

        if (Firststr.contains(ch)) { //如果當(dāng)前字符不能為行首,則當(dāng)前字符為該行的行尾

        endindex = i; //當(dāng)前行結(jié)束的字字符位置

        curwidth = 0; //下一行的行寬

        } else { //當(dāng)前字符可以為行首

        if (Laststr.contains(lastch)) { //上一個(gè)字符不能為行尾,則上一個(gè)字符為下一行的行首

        endindex = i - 2;//當(dāng)前行的行尾為當(dāng)前字符的前兩個(gè)字符

        curwidth = widths[i - 1] + widths[i]; //下一行的行寬

        } else { //上一個(gè)字符可以成為行尾

        endindex = i - 1; //當(dāng)前行的行尾為上一個(gè)字符

        curwidth = widths[i]; //下一行的行寬

        }

        }

        lastch = ch;

        }

        if (!lineclosed) {

        if (ch.equals("n") || i == Text.length() - 1) { //或當(dāng)前字符為換行符或文本最后一個(gè)字符,則當(dāng)前行結(jié)束

        lineclosed = true;

        endindex = i;

        IsCalExtraWidth = false;//不需要計(jì)算字間距

        curwidth = 0;

        }

        }

        if (lineclosed) { //如果當(dāng)前行結(jié)束

        intlen = endindex - startindex + 1;//當(dāng)前行字符個(gè)數(shù)

        float[] linewidths = new float[len]; //當(dāng)前行每一個(gè)字符的寬度

        float linewidth = 0; //當(dāng)前行所有字符輸出寬度之和

        for (int j = startindex; j

        linewidths[j - startindex] = widths[j];

        linewidth = linewidth + widths[j];

        }

        float extrawidth = 0;//調(diào)整字間距

        if (IsCalExtraWidth) { //需要計(jì)算調(diào)整字間距

        extrawidth = (m_LineWidth - linewidth) / len;

        }

        stringlist.add(Text.substring(startindex, endindex + 1)); //當(dāng)前行所包含的字符

        strings.add(new Tlineattr(Text.substring(startindex, endindex + 1), extrawidth, linewidths));

        startindex = endindex + 1; //下一行的起始字符的位置

        }

        }//結(jié)束對字符的歷遍

        if (endindex != (Text.length() - 1)) { //若上一行的行尾不是文本的最后一個(gè)字符,則還剩最后一行

        endindex = Text.length() - 1;

        intlen = endindex - startindex + 1;//當(dāng)前行字符個(gè)數(shù)

        float[] linewidths = new float[len]; //當(dāng)前行每一個(gè)字符的寬度

        float linewidth = 0; //當(dāng)前行所有字符輸出寬度之和

        for (int j = startindex; j

        linewidths[j - startindex] = widths[j];

        linewidth = linewidth + widths[j];

        }

        stringlist.add(Text.substring(startindex, endindex + 1)); //當(dāng)前行所包含的字符

        strings.add(new Tlineattr(Text.substring(startindex, endindex + 1), 0, linewidths));

        }

        }

        成員函數(shù)onDraw()的實(shí)現(xiàn)代碼如下。

        @Override

        protected void onDraw(Canvas canvas) {

        float drawx=0; //繪制字符的橫坐標(biāo)

        float drawy=m_iFontHeight; //繪制字符的縱坐標(biāo)

        for(inti=0;i

        drawx = left_Margin;

        for (int j=0;j

        String ch=strings.get(i).linetext.substring(j,j+1); //取一個(gè)字符

        canvas.drawText(ch,drawx,drawy,mPaint); // 繪制當(dāng)前字符

        drawx=drawx+ strings.get(i).extrawidth+strings.get(i).widths[j]; //下一個(gè)字符的橫坐標(biāo)

        }//結(jié)束當(dāng)前行的循環(huán)

        drawy=drawy+m_iFontHeight; //下一行字符的縱坐標(biāo)

        }//結(jié)束所有行的循環(huán)

        }

        3.2 應(yīng)用實(shí)例

        ExTextView控件的使用與TextView控件的使用是一樣的,這里不作詳細(xì)介紹。對于同一段文本,圖5是Android自帶的TextView顯示效果,圖6是ExTextView的顯示效果。

        4 結(jié)語

        具有兩端對齊功能的ExTextView控件,還不十分完善。比如,為防止英文單詞被截?cái)?,需要加上中英文混合分詞技術(shù),等等。本文只是提供了擴(kuò)展TextView功能一種思路,讀者可以沿著這種思路不斷擴(kuò)展,實(shí)現(xiàn)所需功能。

        亚洲av精二区三区日韩| 在线观看精品国产福利片87| 精品国精品自拍自在线| 我要看免费久久99片黄色| 无码成人一区二区| 91国视频| 国产91熟女高潮一曲区| 免费一区二区高清不卡av| 天天躁日日躁狠狠久久| a观看v视频网站入口免费| 久久精品一区二区三区不卡牛牛| 精品人妻va一区二区三区| 99在线精品免费视频九九视| 无码人妻少妇久久中文字幕蜜桃 | 久草热8精品视频在线观看| 麻豆国产AV网站| 亚洲1区第2区第3区在线播放| 又爽又黄又无遮挡网站| 亚洲av无码国产精品麻豆天美 | 亚洲自偷精品视频自拍| 国产成人麻豆精品午夜福利在线| 无码中文字幕av免费放| 亚洲日本中文字幕高清在线| 狠狠色婷婷久久综合频道日韩| 亚洲Va欧美va国产综合| 国产美女高潮流白浆免费观看| 99久久精品在线视频| 国产激情内射在线影院| 国产精品98视频全部国产| 日韩av免费一区二区| 色欲av蜜桃一区二区三| 国产自产精品露脸刺激91在线| 青青草视频在线免费视频| 亚洲a∨无码精品色午夜| 少妇熟女视频一区二区三区| 国产人妖赵恩静在线视频| 久久精品熟女亚洲av麻| 真人直播 免费视频| 久久精品午夜免费看| 亚洲av网站在线观看一页| 蜜桃麻豆www久久囤产精品|