本來是想做一下ListView生成長(zhǎng)圖的篷角,最后發(fā)現(xiàn)ListView未顯示部分獲取不到画机,就把ListView改成了NestedScrollView包裹LinearLayout冶伞,在LinearLayout中動(dòng)態(tài)添加條目布局。
先看一下效果圖:
布局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ì)算方式是由下圖得來的
圖中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試過之后嗅义,再來記一下,如果有做過的隐砸,也可以留言交流一下之碗。