前言
前幾天設(shè)計(jì)師說要把APP里的一個(gè)界面轉(zhuǎn)成圖片分享出去畜疾,本來想隨意寫個(gè)Dialog算了肚豺,不過看到知乎里面的分享界面覺得還不錯(cuò),反正無聊自己也寫成這樣算了谷异,現(xiàn)在記錄下分尸。
1、界面
據(jù)觀察知乎的分享界面就是用BottomSheetDialog或者BottomSheetDialogFragment寫的歹嘹,所以這里我就用BottomSheetDialogFragment箩绍,具體界面就是
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/share_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="@dimen/dip_fifty_six"
android:layout_marginStart="@dimen/dip_sixteen"
android:gravity="center_vertical"
android:text="@string/share_out_to"
android:textColor="@color/text_black_474c59"
android:textSize="@dimen/sp_sixteen"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/share_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
RecyclerView的LayoutManager就用GridLayoutManager,設(shè)置一行三個(gè)填充尺上。
2材蛛、數(shù)據(jù)
現(xiàn)在來獲取手機(jī)里具有分享功能的APP,在我們的手機(jī)中安裝了的應(yīng)用支持ACTION_SEND的Activity都會(huì)被列入可選列表怎抛。
由于我們需要顯示的內(nèi)容為APP的Icon卑吭、Label就可以了,所以通過PackageManager來獲取ResolveInfo列表就行马绝。具體代碼為:
List<ResolveInfo> resolveList = packageManager.queryIntentActivities(intent, 0);
由于公司項(xiàng)目已經(jīng)集成了微信SDK豆赏,而且由原生分享出去的圖片在微信里并不會(huì)顯示來自哪個(gè)APP,所以在獲取到resolveList后我需要對(duì)獲取到的列表進(jìn)行篩選處理富稻,去掉分享到微信的原生分享Activity數(shù)據(jù)掷邦,這里直接通過微信的包名鑒別,去掉即可椭赋。然后再單獨(dú)在ResolveInfo集合的前面插入自己的數(shù)據(jù)抚岗,這樣還能確保分享到朋友和分享到朋友圈始終在顯示的最前面兩個(gè)。
/**
* 得到支持分享的應(yīng)用
*
* @return 返回支持分享的app集合
*/
public List<ShareItem> scanShreaApp() {
mShareIntent = new Intent(Intent.ACTION_SEND);
mShareIntent.setType("image/*");
PackageManager packageManager = mContext.getPackageManager();
mResolveInfos.clear();
for (ResolveInfo resolveInfo : packageManager.queryIntentActivities(mShareIntent, 0)) {
if (!resolveInfo.activityInfo.packageName.contains("com.tencent.mm")) {
mResolveInfos.add(resolveInfo);
}
}
ArrayList<ShareItem> shareItems = new ArrayList<>();
for (ResolveInfo resolveInfo : mResolveInfos) {
ShareItem shareItem = new ShareItem(resolveInfo.loadLabel(packageManager),
resolveInfo.loadIcon(packageManager));
shareItems.add(shareItem);
}
return shareItems;
}
然后在使用時(shí)將分享給朋友和分享到朋友圈加進(jìn)去:
shareItems.add(new ShareItem("發(fā)送給朋友",
ContextCompat.getDrawable(getContext(), R.drawable.share_icon_wechat)));
shareItems.add(new ShareItem("發(fā)送到朋友圈",
ContextCompat.getDrawable(getContext(), R.drawable.share_icon_moments)));
shareItems.addAll(mShare.scanShreaApp());
mShareItemAdapter.setShareItems(shareItems);
做點(diǎn)擊事件時(shí)單獨(dú)區(qū)分調(diào)用微信分享還是原生分享
mShareItemAdapter.setItmClickListener(new ShareItemAdapter.OnShareItmClickListener() {
@Override
public void onClick(int position) {
mViewBitmap = generateShareImg(time, mArticleTitle, mArticleContent);
mShareUri = BitmapUtil.saveBitmap(mViewBitmap);
if (position == 0) {
shareToWX(SendMessageToWX.Req.WXSceneSession);
} else if (position == 1) {
shareToWX(SendMessageToWX.Req.WXSceneTimeline);
} else {
mShare.share(position - 2, mShareUri);
}
dismiss();
}
});
3哪怔、View轉(zhuǎn)Bitmap
現(xiàn)在來說下View轉(zhuǎn)Bitmap遇到的問題宣蔚,這個(gè)東西還是可以用到很多地方的,比如之前寫彈底部彈窗认境,設(shè)計(jì)師要求彈窗顯示的時(shí)候胚委,背景是當(dāng)前界面的高斯模糊后的效果,在Android里面寫高斯模糊可沒有iOS那么方便元暴,人家直接就是系統(tǒng)提供的一個(gè)控件篷扩,咱們就得把當(dāng)前界面截屏然后轉(zhuǎn)為Bitmap,然后再給它高斯模糊下茉盏,再作為背景鉴未。
其實(shí)一般View轉(zhuǎn)Bitmap就兩個(gè)套路枢冤,
套路一
Bitmap shareBitmap = Bitmap.createBitmap(view.getMeasuredWidth(),
view.getMeasuredHeight(),
Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(shareBitmap);
view.draw(c);
或者
套路二
view.setDrawingCacheEnabled(true);
Bitmap shareBitmap = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
在使用中,如果view是已經(jīng)顯示在界面上了铜秆,那么直接使用時(shí)沒什么問題的淹真,但如果是一個(gè)未曾顯示的界面,想要轉(zhuǎn)換成Bitmap就需要先創(chuàng)建并計(jì)算大小连茧,代碼如下:
View view = View.inflate(this, R.layout.share_out_layout, null);
view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
view.setDrawingCacheEnabled(true);
Bitmap shareBitmap = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
return shareBitmap;
到這里其實(shí)已經(jīng)差不多了核蘸,但是!Pパ薄客扎! 我在Activity中這樣使用一切正常,放在Fragment中用的時(shí)候就GG了罚斗,報(bào)錯(cuò)信息:java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
查看Google搜索出來的結(jié)果徙鱼,有人說測(cè)量view的時(shí)候,如果你的布局中包含有 RelativeLayout )API 為17 或者 低于17 會(huì)報(bào)空指針異常针姿。
但是我去掉RelativeLayout后還是有問題袱吆,再把measure時(shí)的參數(shù)改成int + View.MeasureSpec.EXACTLY ,就確實(shí)不會(huì)報(bào)錯(cuò)了距淫,但是由于view的大小被設(shè)置為固定數(shù)值绞绒,效果太差了。后面試了下套路一榕暇,一切正常E詈狻!拐揭!
所以文章到此結(jié)束.....