Android 生成長(zhǎng)圖并添加水游隽怠(一)

本來是想做一下ListView生成長(zhǎng)圖的篷角,最后發(fā)現(xiàn)ListView未顯示部分獲取不到画机,就把ListView改成了NestedScrollView包裹LinearLayout冶伞,在LinearLayout中動(dòng)態(tài)添加條目布局。
先看一下效果圖:


生成的長(zhǎng)圖.jpg

布局activity_weather_future:

<android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/srl"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

            <android.support.v4.widget.NestedScrollView
                android:id="@+id/nsv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:fillViewport="true">

                <!--設(shè)置paddingBottom是為了在長(zhǎng)圖下方添加logo圖片-->
                <LinearLayout
                    style="@style/MatchMatch"
                    android:orientation="vertical"
                    android:paddingBottom="@dimen/dp_70">

                    <TextView
                        style="@style/MatchWrap"
                        android:layout_marginTop="@dimen/dp_10"
                        android:gravity="center_horizontal"
                        android:tag="skin:future_text_main:textColor"
                        android:text='@{future == null || future.heWeather6.get(0).basic == null?"":future.heWeather6.get(0).basic.location}'
                        android:textColor="@color/future_text_main_default"
                        android:textSize="@dimen/sp_24" />

                    <TextView
                        style="@style/MatchWrap"
                        android:layout_marginTop="@dimen/dp_10"
                        android:gravity="center_horizontal"
                        android:tag="skin:future_text_main:textColor"
                        android:text='@{@string/future_update_time+(future == null || future.heWeather6.get(0).update == null?"":future.heWeather6.get(0).update.loc)}'
                        android:textColor="@color/future_text_main_default"
                        android:textSize="@dimen/sp_16" />

                    <LinearLayout
                        android:id="@+id/ll"
                        style="@style/MatchWrap"
                        android:orientation="vertical" />
                </LinearLayout>
            </android.support.v4.widget.NestedScrollView>
</android.support.v4.widget.SwipeRefreshLayout>

主要操作的就是這個(gè)id為ll的LinearLayout步氏,但也別忘了NestedScrollView响禽,不然不會(huì)滾動(dòng)啊。

頁(yè)面代碼:
獲取數(shù)據(jù)源后荚醒,循環(huán)動(dòng)態(tài)創(chuàng)建條目布局金抡,添加到ll中

mList.clear();
mList.addAll(futureWeatherModel.getHeWeather6().get(0).getDaily_forecast());
ll.removeAllViews();
for (int i = 0; i < mList.size(); i++) {
       ViewDataBinding dataBinding = DataBindingUtil.inflate(LayoutInflater.from(FutureWeatherActivity.this), R.layout.item_weather_future, null, false);
       dataBinding.setVariable(BR.daily, mList.get(i));
       ll.addView(dataBinding.getRoot());
}
srl.setRefreshing(false);

我這里數(shù)據(jù)源是根據(jù)和風(fēng)天氣免費(fèi)api獲取的七天天氣,測(cè)試的時(shí)候可以自己造幾條假數(shù)據(jù)腌且。

ll.setOnLongClickListener(v -> {
            //如果還在刷新梗肝,長(zhǎng)按無效,確保生成長(zhǎng)圖時(shí)铺董,數(shù)據(jù)已經(jīng)獲取到巫击,動(dòng)態(tài)布局已經(jīng)添加完畢。
            if (srl.isRefreshing()) {
                return true;
            }
            Toast.makeText(FutureWeatherActivity.this, "生成長(zhǎng)圖", Toast.LENGTH_SHORT).show();
            //獲取到長(zhǎng)圖bitmap
            Bitmap listViewBitmap = PhotoUtil.getViewGroupBitmap(nsv);
            //展示長(zhǎng)圖
            bitmapDialog = DialogUtil.showBitmapDialog(FutureWeatherActivity.this, listViewBitmap, bitmapCallback);
            return true;
        });

上面就是獲取數(shù)據(jù)精续、根據(jù)數(shù)據(jù)創(chuàng)建條目添加到ll中坝锰、設(shè)置ll的長(zhǎng)按事件,接下來才是本文的重點(diǎn)重付,我抽取成了工具方法放在了PhotoUtil中顷级。

    /**
     * 截取viewGroup內(nèi)容,生成圖片
     *
     * @param viewGroup 容器控件
     * @return 圖片bitmap
     */
    public static Bitmap getViewGroupBitmap(ViewGroup viewGroup) {
        int h = 0;
        Bitmap bitmap;
        for (int i = 0; i < viewGroup.getChildCount(); i++) {
            h += viewGroup.getChildAt(i).getHeight();
        }
        // 創(chuàng)建相應(yīng)大小的bitmap
        bitmap = Bitmap.createBitmap(viewGroup.getMeasuredWidth(), h,Bitmap.Config.ARGB_4444);
        final Canvas canvas = new Canvas(bitmap);
        //獲取當(dāng)前主題背景顏色确垫,設(shè)置canvas背景
        canvas.drawColor(SkinManager.getInstance().getResourceManager().getColor("future_bg"));
        //畫文字水印弓颈,不需要的可刪去下面這行
        drawTextToBitmap(viewGroup.getContext(), canvas, viewGroup.getMeasuredWidth(), h);
        //繪制viewGroup內(nèi)容
        viewGroup.draw(canvas);
        //createWaterMaskImage為添加logo的代碼,不需要的可直接返回bitmap
        return createWaterMaskImage(bitmap, BitmapFactory.decodeResource(viewGroup.getResources(), R.drawable.icon_mark));
    }

這里使用SkinManager換膚功能删掀,獲取了當(dāng)前主題背景顏色翔冀,可用Color.parseColor("#8ac5ec")替代。
想要使用SkinManager的披泪,可以看一下這篇文章:使用SkinManager實(shí)現(xiàn)換膚功能

到這里纤子,生成長(zhǎng)圖功能已經(jīng)實(shí)現(xiàn)了,注意一下我使用的Bitmap.Config是ARGB_4444款票,如果感覺不清晰的話控硼,可改為ARGB_8888,但是圖很大的話可能會(huì)OOM了艾少,如果對(duì)透明度沒啥要求可以改為RGB_565卡乾,再對(duì)圖片壓縮一下就更好了。
下面寫一下添加文字水印drawTextToBitmap方法姆钉,上面的代碼順序不要改變说订,文字是要加在背景上的抄瓦。

/**
     * 給圖片添加水印
     *
     * @param context
     * @param canvas  畫布
     * @param width   寬
     * @param height  高
     */
    public static void drawTextToBitmap(Context context, Canvas canvas, int width, int height) {
        //要添加的文字
        String logo = "皮卡搜";
        //新建畫筆,默認(rèn)style為實(shí)心
        Paint paint = new Paint();
        //設(shè)置顏色陶冷,顏色可用Color.parseColor("#6b99b9")代替
        paint.setColor(SkinManager.getInstance().getResourceManager().getColor("future_text_bg"));
        //設(shè)置透明度
        paint.setAlpha(80);
        //抗鋸齒
        paint.setAntiAlias(true);
        //畫筆粗細(xì)大小
        paint.setTextSize((float) DensityUtil.dip2px(context, 30));
        //保存當(dāng)前畫布狀態(tài)
        canvas.save();
        //畫布旋轉(zhuǎn)-30度
        canvas.rotate(-30);
        //獲取要添加文字的寬度
        float textWidth = paint.measureText(logo);
        int index = 0;
        //行循環(huán)钙姊,從高度為0開始,向下每隔80dp開始繪制文字
        for (int positionY = -DensityUtil.dip2px(context, 30); positionY <= height; positionY += DensityUtil.dip2px(context, 80)) {
            //設(shè)置每行文字開始繪制的位置,0.58是根據(jù)角度算出tan30°,后面的(index++ % 2) * textWidth是為了展示效果交錯(cuò)繪制
            float fromX = -0.58f * height + (index++ % 2) * textWidth;
            //列循環(huán)埂伦,從每行的開始位置開始煞额,向右每隔2倍寬度的距離開始繪制(文字間距1倍寬度)
            for (float positionX = fromX; positionX < width; positionX += textWidth * 2) {
                //繪制文字
                canvas.drawText(logo, positionX, positionY, paint);
            }
        }
        //恢復(fù)畫布狀態(tài)
        canvas.restore();
    }

上面tan30°的計(jì)算方式是由下圖得來的


tan30°.png

圖中A為原canvas,B為旋轉(zhuǎn)-30°后的canvas,width,height為canvas寬高,可以看到旋轉(zhuǎn)后沾谜,X坐標(biāo)向右偏移了膊毁,所以繪制時(shí),應(yīng)向左偏移-tan30°*height,X坐標(biāo)才能與原坐標(biāo)相同基跑。

Y坐標(biāo)雖然也偏移了婚温,但是如圖所示,黑色粗線所示的范圍是可能繪制不到的區(qū)域媳否,且高寬比越大栅螟,繪制不到的區(qū)域越小重绷,手機(jī)的寬度是不變的,當(dāng)高寬比大于圖中height2與width2的比例后尝丐,就能做到全繪制掺逼。

在我測(cè)試的項(xiàng)目里基本不會(huì)出現(xiàn)黑色粗線區(qū)域吃媒,所以我這里沒有對(duì)高度進(jìn)行處理,如有需要吕喘,可在代碼外循環(huán)positionY <= height增加height即可赘那。

文字水印加上了,還有個(gè)添加logo圖標(biāo)的兽泄,一般會(huì)要求圖上有自己公司的標(biāo)識(shí)嘛漓概。

/**
     * 添加logo水印
     *
     * @param src    原圖片
     * @param logo   logo
     * @return 水印圖片
     */
    public static Bitmap createWaterMaskImage(Bitmap src, Bitmap logo) {
        if (src == null) {
            return null;
        }
        //原圖寬高
        int w = src.getWidth();
        int h = src.getHeight();
        //logo寬高
        int ww = logo.getWidth();
        int wh = logo.getHeight();
        //創(chuàng)建一個(gè)和原圖寬高一樣的bitmap
        Bitmap newBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444);
        //創(chuàng)建
        Canvas canvas = new Canvas(newBitmap);
        //繪制原始圖片
        canvas.drawBitmap(src, 0, 0, null);
        //新建矩陣
        Matrix matrix = new Matrix();
        //對(duì)矩陣作縮放處理
        matrix.postScale(0.1f, 0.1f);
        //對(duì)矩陣作位置偏移,移動(dòng)到底部中間的位置
        matrix.postTranslate(0.5f * w - 0.05f * ww, h - 0.1f * wh - 3);
        //將logo繪制到畫布上并做矩陣變換
        canvas.drawBitmap(logo, matrix, null);
        // 保存狀態(tài)
        canvas.save(Canvas.ALL_SAVE_FLAG);// 保存
        // 恢復(fù)狀態(tài)
        canvas.restore();
        return newBitmap;
    }

這樣本文內(nèi)容就完成了病梢,記得一點(diǎn)我這里是只有七條數(shù)據(jù),所以不會(huì)OOM梁肿,如果你需要超長(zhǎng)圖的話蜓陌,一定要進(jìn)行圖片壓縮,我測(cè)的超過30條就很可能崩掉了吩蔑。

雖然實(shí)現(xiàn)了生成長(zhǎng)圖和添加水印钮热,但是我初衷是想在ListView上做的,感覺按照動(dòng)態(tài)添加的思路烛芬,還是可以實(shí)現(xiàn)的隧期,其實(shí)如果列表數(shù)據(jù)過多的話飒责,做這個(gè)意義也不大,而數(shù)據(jù)不多的話仆潮,用這個(gè)也已經(jīng)可以實(shí)現(xiàn)了宏蛉。長(zhǎng)圖的用途無非跟簡(jiǎn)書一樣是為了作分享,簡(jiǎn)書是用webView加載的性置,html頁(yè)面進(jìn)行了數(shù)據(jù)處理拾并,不過也可以嘗試一下。先寫到這吧鹏浅,ListView跟WebView試過之后嗅义,再來記一下,如果有做過的隐砸,也可以留言交流一下之碗。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市季希,隨后出現(xiàn)的幾起案子褪那,更是在濱河造成了極大的恐慌,老刑警劉巖胖眷,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件武通,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡珊搀,警方通過查閱死者的電腦和手機(jī)冶忱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來境析,“玉大人囚枪,你說我怎么就攤上這事±拖” “怎么了链沼?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)沛鸵。 經(jīng)常有香客問我括勺,道長(zhǎng),這世上最難降的妖魔是什么曲掰? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任疾捍,我火速辦了婚禮,結(jié)果婚禮上栏妖,老公的妹妹穿的比我還像新娘乱豆。我一直安慰自己,他們只是感情好吊趾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布宛裕。 她就那樣靜靜地躺著瑟啃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪揩尸。 梳的紋絲不亂的頭發(fā)上蛹屿,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音疲酌,去河邊找鬼蜡峰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛朗恳,可吹牛的內(nèi)容都是我干的湿颅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼粥诫,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼油航!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起怀浆,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤谊囚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后执赡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體镰踏,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年沙合,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了奠伪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡首懈,死狀恐怖绊率,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情究履,我是刑警寧澤滤否,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站最仑,受9級(jí)特大地震影響藐俺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泥彤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一紊搪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧全景,春花似錦、人聲如沸牵囤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至炕贵,卻和暖如春梆奈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背称开。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工亩钟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鳖轰。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓清酥,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蕴侣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子焰轻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,167評(píng)論 25 707
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程,因...
    小菜c閱讀 6,424評(píng)論 0 17
  • 【Android 自定義View之繪圖】 基礎(chǔ)圖形的繪制 一昆雀、Paint與Canvas 繪圖需要兩個(gè)工具辱志,筆和紙。...
    Rtia閱讀 11,669評(píng)論 5 34
  • 太長(zhǎng)不看版:在 Android UI 布局過程中狞膘,遵守一些慣用揩懒、有效的布局原則,可以制作出高效且復(fù)用性高的 UI挽封。...
    Mupceet閱讀 3,842評(píng)論 0 14
  • 詩(shī)篇119:49-64 求你記念向你仆人所應(yīng)許的話已球, 叫我有盼望。 這話將我救活了场仲; 我在患難中和悦,因此得安慰。 驕...
    miya牙簽閱讀 108評(píng)論 0 0