前言
这一篇我们主要实现自定义分享,如下图
实现
我们先看下这布局,可以分解为两部分:一个是顶部为圆角的Layout
,一部分为RecyclerView
,最终我们让这个Dialog
从底部弹出即可
自定义圆角布局
我们首先定义一个CornerFrameLayout
,继承FrameLayout
public class CornerFrameLayout extends FrameLayout {
public CornerFrameLayout(@NonNull Context context) {
this(context, null);
}
public CornerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CornerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public CornerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
}
然后我们给它定义几个自定义属性,圆角的位置,大小等
<declare-styleable name="viewOutLineStrategy">
<attr name="clip_radius" format="dimension"></attr>
<attr name="clip_side" format="enum">
<enum name="all" value="0"></enum>
<enum name="left" value="1"></enum>
<enum name="top" value="2"></enum>
<enum name="right" value="3"></enum>
<enum name="bottom" value="4"></enum>
</attr>
</declare-styleable>
接着我们写一个ViewHelper
辅助类,把设置的逻辑写在这个类里面,以后其他的圆角布局
我们只需要调用这个类中的方法即可
public class ViewHelper {
public static final int RADIUS_ALL = 0;
public static final int RADIUS_LEFT = 1;
public static final int RADIUS_TOP = 2;
public static final int RADIUS_RIGHT = 3;
public static final int RADIUS_BOTTOM = 4;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public static void setViewOutline(View view, AttributeSet attributes, int defStyleAttr, int defStyleRes) {
TypedArray array = view.getContext().obtainStyledAttributes(attributes, R.styleable.viewOutLineStrategy, defStyleAttr, defStyleRes);
int radius = array.getDimensionPixelSize(R.styleable.viewOutLineStrategy_clip_radius, 0);
int hideSide = array.getInt(R.styleable.viewOutLineStrategy_clip_side, 0);
array.recycle();
setViewOutline(view, radius, hideSide);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public static void setViewOutline(View owner, final int radius, final int radiusSide) {
owner.setOutlineProvider(new ViewOutlineProvider() {
@Override
@TargetApi(21)
public void getOutline(View view, Outline outline) {
int w = view.getWidth(), h = view.getHeight();
if (w == 0 || h == 0) {
return;
}
if (radiusSide != RADIUS_ALL) {
int left = 0, top = 0, right = w, bottom = h;
if (radiusSide == RADIUS_LEFT) {
right += radius;
} else if (radiusSide == RADIUS_TOP) {
bottom += radius;
} else if (radiusSide == RADIUS_RIGHT) {
left -= radius;
} else if (radiusSide == RADIUS_BOTTOM) {
top -= radius;
}
outline.setRoundRect(left, top, right, bottom, radius);
return;
}
int top = 0, bottom = h, left = 0, right = w;
if (radius <= 0) {
outline.setRect(left, top, right, bottom);
} else {
outline.setRoundRect(left, top, right, bottom, radius);
}
}
});
owner.setClipToOutline(radius > 0);
owner.invalidate();
}
}
这个类代码主要就是拿到自定义的属性,然后根据具体的属性设置对应的圆角矩形,
这样我们就可以在我们的CornerFrameLayout
调用相应方法就行了
public class CornerFrameLayout extends FrameLayout {
public CornerFrameLayout(@NonNull Context context) {
this(context, null);
}
public CornerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CornerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public CornerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
ViewHelper.setViewOutline(this, attrs, defStyleAttr, defStyleRes);
}
public void setViewOutline(int radius, int radiusSide) {
ViewHelper.setViewOutline(this, radius, radiusSide);
}
}
这个是FrameLayout
,咱们也可以适用LinearLayout
之类的
实现列表
这个列表我们使用RecyclerView
就可以实现,搭配GridLayoutManager
就行,我们先写下这个列表对应的适配器
我们需要通过扫描本地能分享的App
列表
List<ResolveInfo> shareitems = new ArrayList<>();
private void queryShareItems() {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("text/plain");
List<ResolveInfo> resolveInfos = getContext().getPackageManager().queryIntentActivities(intent, 0);
for (ResolveInfo resolveInfo : resolveInfos) {
String packageName = resolveInfo.activityInfo.packageName;
if (TextUtils.equals(packageName, "com.tencent.mm") || TextUtils.equals(packageName, "com.tencent.mobileqq")) {
shareitems.add(resolveInfo);
}
}
}
接着就可以写我们的适配器了
private class ShareAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final PackageManager packageManager;
public ShareAdapter() {
packageManager = getContext().getPackageManager();
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View inflate = LayoutInflater.from(getContext()).inflate(R.layout.layout_share_item, parent, false);
return new RecyclerView.ViewHolder(inflate) {
};
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
ResolveInfo resolveInfo = shareitems.get(position);
PPImageView imageView = holder.itemView.findViewById(R.id.share_icon);
Drawable drawable = resolveInfo.loadIcon(packageManager);
imageView.setImageDrawable(drawable);
TextView shareText = holder.itemView.findViewById(R.id.share_text);
shareText.setText(resolveInfo.loadLabel(packageManager));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String pkg = resolveInfo.activityInfo.packageName;
String cls = resolveInfo.activityInfo.name;
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.setComponent(new ComponentName(pkg, cls));
intent.putExtra(Intent.EXTRA_TEXT, shareContent);
getContext().startActivity(intent);
if (mListener != null) {
mListener.onClick(v);
}
dismiss();
}
});
}
@Override
public int getItemCount() {
return shareitems == null ? 0 : shareitems.size();
}
}
当我们点击某个Item
的时候跳转到对应的App
,这样整个分享的Dialog
就可以完全写完了
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
layout = new CornerFrameLayout(getContext());
layout.setBackgroundColor(Color.WHITE);
layout.setViewOutline(PixUtils.dp2px(20), ViewHelper.RADIUS_TOP);
RecyclerView gridView = new RecyclerView(getContext());
gridView.setLayoutManager(new GridLayoutManager(getContext(), 4));
shareAdapter = new ShareAdapter();
gridView.setAdapter(shareAdapter);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
int margin = PixUtils.dp2px(20);
params.leftMargin = params.topMargin = params.rightMargin = params.bottomMargin = margin;
params.gravity = Gravity.CENTER;
layout.addView(gridView, params);
setContentView(layout);
getWindow().setGravity(Gravity.BOTTOM);
getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
queryShareItems();
}
工具类
我们上一次写点赞和踩得时候写了一个行为类InteractionPresenter
,我们也把这个分享写在这里面,同时每次分享的时候我们都改变下分享的个数
/**
* 打开分享面板
*/
public static void openShare(Context context, Feed feed) {
String shareContent = feed.feeds_text;
if (!TextUtils.isEmpty(feed.url)) {
shareContent = feed.url;
} else if (!TextUtils.isEmpty(feed.cover)) {
shareContent = feed.cover;
}
ShareDialog shareDialog = new ShareDialog(context);
shareDialog.setShareContent(shareContent);
shareDialog.setShareItemClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ApiService.get(URL_SHARE)
.addParam("itemId", feed.itemId)
.execute(new JsonCallback<JSONObject>() {
@Override
public void onSuccess(ApiResponse<JSONObject> response) {
if (response.body != null) {
int count = response.body.getIntValue("count");
feed.getUgc().setShareCount(count);
}
}
@Override
public void onError(ApiResponse<JSONObject> response) {
showToast(response.message);
}
});
}
});
shareDialog.show();
}
接着我们和我们上一篇点赞和踩一样,我们在我们的xml
中写上点击事件
android:onClick="@{()->InteractionPresenter.openShare(((Context)lifeCycleOwner),feed)}"
我们看下效果