在規定區域內自動調整文字位置

問題

最近在作一個需求,就是塗鴉時,在繪製的圖形旁邊經過文字顯示相關信息.先給你們看看最終的效果:java

效果圖

一開始的時候被這個問題難倒了,怎麼找到合適的位置顯示文字信息,讓它們既不超出顯示範圍,又互不重疊?git

解決方案

若是考慮不能重疊的問題,就須要在圖形四周的位置遍歷一遍直到沒有跟其餘文字重疊,加上繪製的圖形是能夠移動問題,這樣問題就更復雜了.因而我只能簡單化,尋找代價低又基本能知足要求的方式.github

首先,定義一個適配規則:文字優先顯示在左邊,若是超出顯示區域則直接顯示在右邊,這種右邊的狀況下若是也超出了顯示區域,則往左邊偏移文字文字,使其恰好在顯示區域邊上.肯定了左右位置後,接着處理垂直方向,文字優先顯示在跟圖形最上邊位置齊平的位置,若是文字底部超出顯示區域,則往上偏移文字,使其底部恰好在顯示區域底邊.canvas

以矩形爲例,顯示效果以下:框架

分析圖

對照規則,標註以下:優化

文字優先顯示在左邊(圖1,2,4,6,7,10),若是超出顯示區域則直接顯示在右邊(圖3,5),這種右邊的狀況下若是也超出了顯示區域,則往左邊偏移文字文字,使其恰好在顯示區域邊上(圖9).肯定了左右位置後,接着處理垂直方向,文字優先顯示在跟圖形最上邊位置齊平的位置(除圖8外的全部圖形),若是文字底部超出顯示區域,則往上偏移文字,使其底部恰好在顯示區域底邊(圖8).this

這樣就限定了圖像顯示在規定區域內啦!spa

實現

最後給出主要代碼的代碼實現,包括了矩形,圓,線的文字位置調整:rest

String msg = getInfo();
        StaticLayout textStaticLayout = new StaticLayout(msg, mTextPaint, (int) getMaxWidth(msg, mTextPaint) + 1, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
        mTextBounds.set(0, 0, textStaticLayout.getWidth(), textStaticLayout.getHeight());
        float x = 0, y = 0;
        if (getShape() == DoodleShape.HOLLOW_RECT || getShape() == DoodleShape.HOLLOW_CIRCLE) {
            // 左右限定
            float diff = -mTextPaint.getTextSize() / 3 ;
            x = mShapeBounds.right - diff;  // 優先在右
            y = mShapeBounds.top;
            if (x + getLocation().x + mTextBounds.width() > getDoodle().getBitmap().getWidth()) { // 超過右邊邊界,移到左邊
                x = mShapeBounds.left + diff - textStaticLayout.getWidth();
                if (x + getLocation().x < 0) {&emsp; //&emsp;左邊邊界限定
                &emsp;&emsp;x = 0;
            &emsp;&emsp;}
            }

            // 上下限定,優先在上
            if (y + getLocation().y + mTextBounds.height() > getDoodle().getBitmap().getHeight()) {
                y = mShapeBounds.bottom - textStaticLayout.getHeight();
            }
            if (y + getLocation().y < 0) {
                y = 0;
            }
        } else { // 線
            PointF sxy = this.mSxy; // 起點
            PointF dxy = this.mDxy; // 終點
            if (this.mSxy.x > this.mDxy.x) { // 保證起點在左,終點在右的相對位置
                sxy = this.mDxy;
                dxy = this.mSxy;
            }
            // 左右限定
            x = dxy.x + mTextPaint.getTextSize() / 3;  // 優先在右
            y = dxy.y;
            if (x + getLocation().x + mTextBounds.width() > getDoodle().getBitmap().getWidth()) { // 超過右邊邊界,移到左邊
                x = sxy.x - mTextPaint.getTextSize() / 3 - textStaticLayout.getWidth();
                y = sxy.y;
                if (x + getLocation().x < 0) {  //&emsp;左邊邊界限定
                    x = 0;
                }
            }
           
            // 上下限定, 優先在上
            if (y + getLocation().y + mTextBounds.height() > getDoodle().getBitmap().getHeight()) {
                y = y - ((y + getLocation().y + mTextBounds.height()) - getDoodle().getBitmap().getHeight());
            }
            if (y + getLocation().y < 0) {
                y = 0;
            }
        }
        canvas.save();
        canvas.translate(x, y);
        textStaticLayout.draw(canvas);
        canvas.restore();
複製代碼

總結

上面僅是處理文字邊界範圍內顯示,除此以外還會存在文字之間重疊的問題.這裏咱們能夠參照上面的思路,優化邏輯,好比在左右限定時,若是知足右邊顯示,則增長判斷是否跟其餘圖形的文字重疊,若是不重疊則肯定右邊顯示,若是有重疊則換成在左邊顯示.思路很簡單即在每一步判斷後再增長一條更嚴格的判斷,固然咱們沒法作到全部文字都不重疊(否則須要太多判斷條件),只要能作到儘可能不重疊便可.code

文中一開始的效果的塗鴉代碼在個人開源框架的開源項目>>>>開源項目Doodle!一個功能強大,可自定義和可擴展的塗鴉框架。謝謝你們支持!!!

相關文章
相關標籤/搜索