现在很多的应用基本都会集成分享这个功能,该功能包括系统分享(比如邮件,短信)和第三方分享(比如QQ和微信)。其中有些公司会选择使用第三方的库来简化这些操作,加快开发,用的比较多的比如友盟社会化分享SDK,缺点就是自由度太低,因为可能你仅仅只是需要QQ和微信,其他的公司就会选择自己导入所需要的第三方SDK来自定义分享功能,自由度高,于是这篇博客主要来介绍后一种自定义分享功能的案例demo,下图是demo的运行效果:
具体分析一下源码,由于分享的内容根据需求的不同而不同,为了简单起见,我们就以最常用的图文+链接的形式为例,其他情况何以根据需求修改相关类。第一步定义分享的实体类:
ShareModel.java
public class ShareModel { /** 分享的类型,图片,文字等 */ public int type; /** 分享的标题 */ public String title; /** 分享内容 */ public String content; /** 分享的链接 */ public String shareUrl; /** 分享图片的网络url */ public ArrayList<String> imageUrl; /** 分享图片的本地path路径 */ public ArrayList<String> imagePath;}
这个类定义了分享的基本数据类型(按照需求修改该类即可,比如可以添加视频语音之类)。接着我们建立各自的分享模块用来区分不同的分享(这里以系统和QQ分享为例),并且每个分享模块都要继承自同一个接口IShare:
IShare.java
public interface IShare { /** * @param model 调用分享的实体 * @param context 上下文 * @param type 调用该分享的类别 * @param callback 分享回调 */ void doShare(ShareModel model, Context context, int type, IShareCallback callback); /** * 该函数在{@link android.app.Activity#onActivityResult(int, int, Intent)} * 调用,用来处理分享的回调,比如QQ和系统分享(微信这种不需要在onActivityResult中处理的直接返回false即可) * @return 是否为该分享的回调 */ boolean doShareCallback(int requestCode, int resultCode, Intent data);}
该接口定义了两个函数,一个是分享函数,另一个是分享的回调函数,系统分享和QQ分享的相关类继承该接口实现这两个函数:
QQ分享TencentShare .class
public class TencentShare implements IShare { @Override public void doShare(ShareModel model, Context context, int type, IShareCallback callback) { //具体看源码 } @Override public boolean doShareCallback(int requestCode, int resultCode, Intent data) { //具体看源码 }}
系统分享SystemShare.class
public class SystemShare implements IShare { @Override public void doShare(ShareModel model, Context context, int type, IShareCallback callback) { //具体看源码 } @Override public boolean doShareCallback(int requestCode, int resultCode, Intent data) { //具体看源码 }}
如果需要集成其他第三方分享,新建相关类实现相关函数即可。然后就是最重要的管理类了,看看该类的源码:
public class ShareManager { private Activity activity; private IShareCallback callback; private PopupWindow popupWindow; /** 最新一次调用分享的对象 */ private IShare shareObject; /** * @param callback 分享出去的回调 */ public ShareManager(Activity activity, IShareCallback callback){ this.activity = activity; this.callback = callback; //初始化Share枚举类 Share demo = Share.QQ_FRIEND; } /** * 用来展示分享popUpWindow * @param model 分享出去的实体 */ public void show(final ShareModel model) { if (popupWindow == null) { popupWindow = new ShareGridViewPopupWindow(activity, new ShareGridViewPopupWindow.IShareClickCallback() { @Override public void onShareCallback(int position) { try { Class<? extends IShare> clazz = Share.values()[position].getShareClass(); shareObject = clazz.newInstance(); shareObject.doShare(model, activity, Share.values()[position].getType(), callback); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }); popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() { @Override public void onDismiss() { popupWindow = null; } }); } popupWindow.showAtLocation(activity.getWindow().getDecorView(), Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0); } /** * 用来在activity的onActivityResult函数中注册分享回调,比如QQ和系统分享 * @return 是否是分享回调,如果是,返回true,表明activity不用处理相关result */ public boolean registerOnActivityCallback(int requestCode, int resultCode, Intent data){ return shareObject!=null && shareObject.doShareCallback(requestCode, resultCode, data); } /** * 在此处动态添加分享模块 */ public enum Share { QQ_FRIEND("QQ", R.mipmap.logo_qq, 0, TencentShare.class), QQ_ZONE("QQ空间", R.mipmap.logo_qzone, 1, TencentShare.class), MAIL("邮件", R.mipmap.logo_email, 0, SystemShare.class), MESSAGE("信息", R.mipmap.logo_shortmessage, 1, SystemShare.class); private String name; private int drawable; private Class<? extends IShare> shareClass; private int type; Share(String name, int drawable, int type, Class<? extends IShare> shareClass){ this.name = name; this.drawable = drawable; this.type = type; this.shareClass = shareClass; } public String getName(){ return name; } public int getDrawableId(){ return drawable; } public int getType(){ return type; } public Class<? extends IShare> getShareClass() { return shareClass; } }}
该类使用一个enum来集中定义所有的分享,每个分享都会有一个名字和图片用来展示,而点击效果的回调则是由相关继承自IShare接口的class类对象调用doShare函数来进行处理,这么做的好处是利于管理和以后的分享类别的增加和删除。该类中还有一个registerOnActivityCallback函数,该函数是用来在Activity中的onActivityResult中注册分享回调,通知相关分享的回调成功与否。
我们在这里使用popupWindow来弹出分享框,于是需要自定义一个popupWindow:
ShareGridViewPopupWindow.java类:
public class ShareGridViewPopupWindow extends PopupWindow { private View mMenuView; private LayoutInflater inflater; private GridView gridView; private TextView tv_dismiss; private Activity context; private View view; public ShareGridViewPopupWindow(Activity context, final IShareClickCallback callback) { super(); this.context = context; inflater = (LayoutInflater) context.getSystemService(Service.LAYOUT_INFLATER_SERVICE); mMenuView = inflater.inflate(R.layout.share_popupwindow, null); gridView = (GridView) mMenuView.findViewById(R.id.gridview); tv_dismiss = (TextView) mMenuView.findViewById(R.id.tv_dismiss); gridView.setAdapter(new GridViewAdapter()); gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (callback != null) callback.onShareCallback(position); dismiss(); } }); this.setAnimationStyle(R.style.share_PopupAnimation); //http://stackoverflow.com/questions/3121232/android-popup-window-dismissal this.setBackgroundDrawable(new BitmapDrawable(null,"")); this.setFocusable(true); tv_dismiss.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { dismiss(); } }); this.setContentView(mMenuView); this.setWidth(LayoutParams.MATCH_PARENT); this.setHeight(LayoutParams.WRAP_CONTENT); //点击popUpWindow其他部分消失 mMenuView.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { int height = mMenuView.findViewById(R.id.pop_layout).getTop(); int y = (int) event.getY(); if (event.getAction() == MotionEvent.ACTION_UP) { if (y < height) { dismiss(); } } return true; } }); //增加popUpWindow其他部分的灰色效果 view = new View(context); view.setBackgroundColor(Color.parseColor("#b0000000")); ((ViewGroup)context.getWindow().getDecorView().getRootView()).addView(view); } private class GridViewAdapter extends BaseAdapter { @Override public int getCount() { return ShareManager.Share.values().length; } @Override public Object getItem(int position) { return ShareManager.Share.values()[position]; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = inflater.inflate(R.layout.share_grid_item, null); } convertView.findViewById(R.id.iv_image).setBackgroundResource(ShareManager.Share.values()[position].getDrawableId()); ((TextView)convertView.findViewById(R.id.tv_text)).setText(ShareManager.Share.values()[position].getName()); return convertView; } } @Override public void dismiss() { super.dismiss(); ((ViewGroup)context.getWindow().getDecorView().getRootView()).removeView(view); } public interface IShareClickCallback { void onShareCallback(int position); }}
该popupWindow使用gridView来进行布局,大家可以根据需求修改该布局,关于popupWindow的使用我这里说几点:第一点是popupWindow点击外部和返回键消失的处理,点击外部消失需要使用setOnTouchListener函数来监控用户触摸的位置,按下返回键的处理需要先使用setBackgroundDrawable函数给该popupWindow设置一个背景,接着使用setFocusable函数设置焦点;第二点是外侧的灰色背景,我这里使用的是当popupWindow展示的时候在decorView上加入一个透明黑色的view,在dismiss的时候去掉,这样效果就达到了。
基本的思想就介绍完了,很简单,具体的大家可以去看源码:
https://github.com/zhaozepeng/ShareManager
- 1楼u0107866786小时前
- 感谢楼主的分享,学习了`(*∩_∩*)′
- Re: zhao_zepeng5小时前
- 回复u010786678n嗯嗯嗯,一起进步啊