Androidリッチテキストエディタ(3):テキストスタイル

5565 ワード

リッチテキストエディタにとっては、画像を挿入する以外に、最も重要な機能の一つは異なる文字スタイルを提供することです.主に、太字、斜体、文字の色の切り替えなどがあります.写真と違って、私達は文字スタイルの製品に対する需要は二つの方面を含みます.
  • テキストスタイルを設定します.
  • は、テキストの現在のスタイルを取得する.
  • 設定を先に言ってください.この記事を参考にしてもいいです.http://hunankeda110.iteye.com/blog/1420470
    //         
    msp.setSpan(new ForegroundColorSpan(Color.MAGENTA), 12, 15, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);  //           
      
    //         
    msp.setSpan(new BackgroundColorSpan(Color.CYAN), 15, 18, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);  //          
    
    //        ,  ,  ,     
    msp.setSpan(new StyleSpan(android.graphics.Typeface.NORMAL), 18, 20, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);  //    
    msp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 20, 22, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);  //    
    msp.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 22, 24, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);  //    
    msp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD_ITALIC), 24, 27, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);  //   
    
    これは実はこのシリーズの文章で紹介されています.spannable stringの基本的な使い方です.しかし、拡張性がよく、より工程化された方法を書くために、修正、検索、追加などの異なる需要を満たすためには、これだけは無理です.インターネットで多くのソースと資料を探した後、このプロジェクトの書き方を紹介します.https://github.com/1gravity/Android-RTEditor このプロジェクトが実现したリッチテキストエディタは非常に强力で、ほぼすべてのテキストを完成させることができます.このプロジェクトでは工場のような方法を採用しています.Effect抽象基質を提供しています.すべての文字スタイルはこの基質から継承され、対応するSpanの構造を担当しています.ベースクラスではapplyメソッドを実現し、異なる文字スタイルを適用します.以下のように、BoldEffectの例である.
    public class BoldEffect extends Effect {
        @Override
        protected Class extends Span> getSpanClazz() {
            return BoldSpan.class;
        }
    
        @Override
        protected Span newSpan(Boolean value) {
            return value ? new BoldSpan() : null;
        }
    }
    
    BoldSpanの実現は以下の通りである.
    public class BoldSpan extends StyleSpan implements Span {
        public BoldSpan() {
            super(Typeface.BOLD);
        }
    
        @Override
        public Boolean getValue() {
            return Boolean.TRUE;
        }
    }
    
    Effectのソースコードを見て、上のサブクラスのgetSpanClazzとnewSpanの応用シーンを理解します.まず、現在のスタイルが選択されたテキストに存在するかどうかを判断します.コードは以下の通りです.
    final public boolean existsInSelection(RichEditText editor, int spanType) {
        Selection expandedSelection = getExpandedSelection(editor, spanType);
        if (expandedSelection != null) {
            Span[] spans = getSpans(editor.getText(), expandedSelection);
            return spans.length > 0;
        }
    
        return false;
    }
    
    final public Span[] getSpans(Spannable str, Selection selection) {
        Class extends Span> spanClazz = getSpanClazz();
        Span[] result = str.getSpans(selection.start(), selection.end(), spanClazz);
        return result != null ? result : (Span[]) Array.newInstance(spanClazz);
    }
    
    ここで使用するgetSpans法はSpannedインターフェースで定義され、Spannable Stringで実現される.インターフェースの定義は以下の通りです.
    /**
     * Return an array of the markup objects attached to the specified
     * slice of this CharSequence and whose type is the specified type
     * or a subclass of it.  Specify Object.class for the type if you
     * want all the objects regardless of type.
     */
    public  T[] getSpans(int start, int end, Class type);
    
    上の呼び出しの過程では、サブクラスに重載されたget SpanClazz方法が使用されています.次に、アプリ方法の実現を見てみます.
    
    public void apply(RichEditText editor, int start, int end, V value) {
        Selection selection = new Selection(start, end);
        Spannable str = editor.getText();
    
        // expand the selection to "catch" identical leading and trailing styles
        Selection expandedSelection = selection.expand(1, 1);
        for (Span span : getSpans(str, expandedSelection)) {
            boolean equalSpan = span.getValue() == value;
            int spanStart = str.getSpanStart(span);
            if (spanStart < selection.start()) {
                if (equalSpan) {
                    selection.offset(selection.start() - spanStart, 0);
                }
                else {
                    str.setSpan(newSpan(span.getValue()), spanStart, selection.start(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                }
            }
            int spanEnd = str.getSpanEnd(span);
            if (spanEnd > selection.end()) {
                if (equalSpan) {
                    selection.offset(0, spanEnd - selection.end());
                }
                else {
                    str.setSpan(newSpan(span.getValue()), selection.end(), spanEnd, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
                }
            }
            str.removeSpan(span);
        }
    
        if (value != null) {
            Span newSpan = newSpan(value);
            if (newSpan != null) {
                int flags = selection.isEmpty() ? Spanned.SPAN_INCLUSIVE_INCLUSIVE : Spanned.SPAN_EXCLUSIVE_INCLUSIVE;
                str.setSpan(newSpan, selection.start(), selection.end(), flags);
            }
        }
    }
    
    この一番重要なコードはif(value!=null)から始まり、スタイルのspanを設定します.その中にはサブクラスのnewSpan方法が使われています.私たちは、セレクションが空なら、Spanned.SPAN_に設定されていることに気づきました.INCLUSIVE_INCLUSIVEは、空ではなくSpanned.SPAN_です.EXCLUSIVE_INCLUSIVE.一般的に、文字スタイルはSPAN_に設定するべきです.EXCLUSIVE_INCLUSIVEは、後から追加される文字を同じ形で使用することができます.ただし、セレクションが空の場合は前後に同じ形をとる必要があり、新たな文字を挿入することで効果が得られます.前のforループの部分は、実際には検出前のテキストにスタイルspanが設定されていますか?例えば、一段の文字の長さが20の場合、1文字から8文字までAスタイルが設定されています.12文字から20文字までBスタイルが設定されています.今は5-15文字にCスタイルを設定します.次の3つのステップを行います.
  • はAスタイルのspanを1-5文字に調整します.
  • Bスタイルのspanを16-20文字に調整します.
  • Cスタイルのspanを5-15文字に設定します.
  • 上記のロジックと照らし合わせて、フォームサイクルのコードを見ればよく分かります.皆さんもコードと照らし合わせてみてもいいです.上記のリンクを確認してください.もちろん、私のプロジェクトコードでも大丈夫です.中にはBoldEffectしかありません.でも、Effectのような実現があります.でも、Android d-RTEditorのコードを参考にしました.自分のプロジェクトのリンクを貼り付けてください.https://github.com/InnerNight/rich-edit-text