转发备注:https://blog.csdn.net/ctianju/article/details/122109664
背景淘宝,京东等购物类App订单列表都有“更多”着操作,比如删除订单,查看物流等操作;
分析Android自带的PopWindow组件就能很好的满足,但是还有问题需要分析解决:
1、弹框的方向问题,如果列表滑动到底部需要向上弹,顶部就向下弹;
解决:计算点击“更多”文字的位置,来动态的改变弹出的方向
2、弹框的背景样式;
解决:最简单利用点9图片作为背景
3、订单列表的 item 数据返回问题
解决:和后端沟通,更多操作的按钮就放到一个list,普通的就放到一个list
4、列表按钮太多放不下问题
解决:利用横向滚动的HorizontalScrollView 动态添加按钮进去
1、重写PopupWindow
public class ActionMorePopWindow extends PopupWindow {
private Context context;
private View conentView;
private RecyclerView listView;
private ActionSelectPopularAdapter selectAdapter;
List typeSelectlist = new ArrayList();
int[] location = new int[2];
private OnPopWindowItemListener onItemListener;
private LinearLayout llParent;
public interface OnPopWindowItemListener {
void OnItemListener(int position, OrderActionBtnEntity orderActionEntity);
}
public void setOnItemMyListener(OnPopWindowItemListener onItemListener) {
this.onItemListener = onItemListener;
}
public ActionMorePopWindow(Context context) {
this.context = context;
initView();
}
public ActionMorePopWindow(Context context, List typeSelectlist) {
this.context = context;
this.typeSelectlist = typeSelectlist;
initView();
}
private void initView() {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.conentView = inflater.inflate(R.layout.popwindow, null);
// 设置PopupWindow的View
this.setContentView(conentView);
// 设置PopupWindow弹出窗体的宽
this.setWidth(LinearLayout.LayoutParams.WRAP_CONTENT);
// 设置PopupWindow弹出窗体的高
this.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
// 设置PopupWindow弹出窗体可点击
this.setFocusable(true);
this.setOutsideTouchable(true);
// 刷新状态
this.update();
// 实例化一个ColorDrawable颜色为半透明
ColorDrawable dw = new ColorDrawable(0000000000);
// 点back键和其他地方使其消失,设置了这个才能触发onDismisslistener ,设置其他控件变化等操作
this.setBackgroundDrawable(dw);
this.listView = conentView.findViewById(R.id.lv_list);
//设置适配器
this.selectAdapter = new ActionSelectPopularAdapter(typeSelectlist, context);
this.listView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false));
llParent = conentView.findViewById(R.id.llParent);
SpacingDecoration itemDecoration = new SpacingDecoration(context, 1);
this.listView.addItemDecoration(itemDecoration);
this.listView.setAdapter(selectAdapter);
this.selectAdapter.setOnItemClickerListener(new ActionSelectPopularAdapter.OnItemClickerListener() {
@Override
public void onItemClick(int position) {
if (isShowing()) {
dismiss();
}
onItemListener.OnItemListener(position, typeSelectlist.get(position));
}
});
this.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss() {
}
});
}
//设置数据
public void setDataSource(List typeSelectlist) {
this.typeSelectlist = typeSelectlist;
this.selectAdapter.notifyDataSetChanged();
}
public void showPopupWindow(View v) {
v.getLocationOnScreen(location); //获取控件的位置坐标
//获取自身的长宽高
conentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
if (location[1] > DensityUtil.INSTANCE.getScreenHeight(v.getContext()) / 2 + 100) {
//若是控件的y轴位置大于屏幕高度的一半,向上弹出,
llParent.setBackground(v.getContext().getDrawable(R.drawable.order_doctor_more_up_bg));
//显示指定控件的上方
// 偏移距离根据UI的慢慢调整
this.showAtLocation(v, Gravity.NO_GRAVITY, location[0] - DensityUtil.INSTANCE.dp2px(10), location[1] - listView.getMeasuredHeight()-DensityUtil.INSTANCE.dp2px(17));
} else {
llParent.setBackground(v.getContext().getDrawable(R.drawable.order_doctor_more_down_bg));
//显示指定控件的下方
// 偏移距离根据UI的慢慢调整
this.showAsDropDown(v, 0- DensityUtil.INSTANCE.dp2px(10), 0);
}
}
}
2、绘制popwindow布局
popwindow.xml
3、绘制popwindow 里面RecyclerView的item布局
pop_item_action.xml
4、ActionSelectPopularAdapter
public class ActionSelectPopularAdapter extends RecyclerView.Adapter{ private List mData = new ArrayList<>(); private Context context; private OnItemClickerListener onItemClickerListener; public ActionSelectPopularAdapter(List mData, Context context) { this.mData.clear(); this.mData.addAll(mData); this.context = context; } public void setOnItemClickerListener(OnItemClickerListener onItemClickerListener) { this.onItemClickerListener = onItemClickerListener; } @Override public MoreActionHolder onCreateViewHolder(@NonNull @NotNull ViewGroup parent, int viewType) { View itemRoot = LayoutInflater.from(parent.getContext()).inflate(R.layout.pop_item_action, parent, false); return new MoreActionHolder(itemRoot); } @Override public void onBindViewHolder(MoreActionHolder holder, int position) { OrderActionBtnEntity item = this.mData.get(position); holder.bind(item); } @Override public int getItemCount() { return mData.size(); } class MoreActionHolder extends RecyclerView.ViewHolder { private final TextView orderActionTitle; public MoreActionHolder(@NonNull @NotNull View itemView) { super(itemView); orderActionTitle = itemView.findViewById(R.id.orderActionTitle); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onItemClickerListener.onItemClick(getAdapterPosition()); } }); } public void bind(OrderActionBtnEntity item) { orderActionTitle.setText(item.getName()); } } public interface OnItemClickerListener{ void onItemClick(int position); } }
5、OrderActionBtnEntity
// 订单的操作按钮
class OrderActionBtnEntity {
var color: String? = null
var type: Int = -1 //
var name: String? = null //
constructor(type: Int, name: String?,color: String? ) {
this.type = type
this.name = name
this.color = color
}
}
6、两个弹框背景的点9图片
1、order_doctor_more_up_bg
2、order_doctor_more_down_bg
1、activity_main.xm
2、MainActivity 包括构造数据源
class MainActivity : AppCompatActivity() {
private val normalButtonsList = mutableListOf()
private val normalButtonsList2 = mutableListOf()
private val normalButtonsList3 = mutableListOf()
private val moreButtonsList = mutableListOf()
private val moreButtonsList2 = mutableListOf()
private val moreButtonsList3 = mutableListOf()
private val dataList = mutableListOf()
companion object {
const val DELETe_TYPE = 1 // 删除按钮类型
const val GO_SHOPPING_CART_TYPE = 2 // 再次购买按钮
const val MAKE_AN_INVOICE_TYPE = 3 // 去咨询
const val MAKE_AN_SHARE_MORE_TYPE = 4 // 去咨询
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initData()
val adapter = MainRvAdapter(dataList, this)
mainRvList.layoutManager = LinearLayoutManager(this)
val spacingDecoration = SpacingDecoration(this, 10)
spacingDecoration.setOutSpacing(this, 15, 12, 15, 12)
mainRvList.addItemDecoration(spacingDecoration)
mainRvList.adapter = adapter
}
// 初始化数据源
private fun initData() {
// 普通按钮
normalButtonsList.add(OrderActionBtnEntity(DELETE_TYPE, "支付", "#999999"))
normalButtonsList.add(OrderActionBtnEntity(DELETE_TYPE, "在线咨询", "#999999"))
normalButtonsList.add(OrderActionBtnEntity(DELETE_TYPE, "分享", "#999999"))
normalButtonsList.add(OrderActionBtnEntity(MAKE_AN_SHARE_MORE_TYPE, "分享更多", "#999999"))
// 普通按钮2
normalButtonsList2.add(OrderActionBtnEntity(DELETE_TYPE, "支付", "#999999"))
normalButtonsList2.add(OrderActionBtnEntity(DELETE_TYPE, "在线咨询", "#999999"))
// 普通按钮3
normalButtonsList3.add(OrderActionBtnEntity(DELETE_TYPE, "支付", "#999999"))
normalButtonsList3.add(OrderActionBtnEntity(DELETE_TYPE, "分享", "#999999"))
// 更多按钮
moreButtonsList.add(OrderActionBtnEntity(DELETE_TYPE, "删除订单", "#999999"))
moreButtonsList.add(OrderActionBtnEntity(GO_SHOPPING_CART_TYPE, "加入购物车", "#999999"))
moreButtonsList.add(OrderActionBtnEntity(MAKE_AN_INVOICE_TYPE, "申请开票", "#999999"))
// 更多按钮2
moreButtonsList2.add(OrderActionBtnEntity(DELETE_TYPE, "删除订单", "#999999"))
moreButtonsList2.add(OrderActionBtnEntity(MAKE_AN_INVOICE_TYPE, "申请开票", "#999999"))
// 更多按钮3
moreButtonsList3.add(OrderActionBtnEntity(DELETE_TYPE, "删除订单", "#999999"))
dataList.add(OrderEntity("商品----1", "¥ 100.0 元", normalButtonsList, moreButtonsList))
dataList.add(OrderEntity("商品----2", "¥ 10.0元", normalButtonsList2, moreButtonsList2))
dataList.add(OrderEntity("商品----3", "¥11.0元", normalButtonsList3, moreButtonsList3))
dataList.add(OrderEntity("商品----4", "¥ 1000.0元", normalButtonsList, moreButtonsList))
dataList.add(OrderEntity("商品----5", "¥ 1000.0元", normalButtonsList, moreButtonsList))
dataList.add(OrderEntity("商品----6", "¥ 1000.0元", normalButtonsList, moreButtonsList))
dataList.add(OrderEntity("商品----7", "¥ 1000.0元", normalButtonsList, moreButtonsList))
}
}
3、item_order.xml
4、MainRvAdapter ->>>>> RecyclerView.Adapter
public class MainRvAdapter extends RecyclerView.Adaptergithub地址 总结{ private List mData = new ArrayList<>(); public MainRvAdapter(List mData, Context context) { this.mData.clear(); this.mData.addAll(mData); } @Override public MoreActionHolder onCreateViewHolder(@NonNull @NotNull ViewGroup parent, int viewType) { View itemRoot = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_order, parent, false); return new MoreActionHolder(itemRoot); } @Override public void onBindViewHolder(MoreActionHolder holder, int position) { OrderEntity item = this.mData.get(position); holder.bind(item); } @Override public int getItemCount() { return mData.size(); } class MoreActionHolder extends RecyclerView.ViewHolder { private final TextView name; private final TextView price; private final TextView tv_moreBtn; private final LinearLayout normalBtnlay; public MoreActionHolder(@NonNull @NotNull View itemView) { super(itemView); name = itemView.findViewById(R.id.orderName); price = itemView.findViewById(R.id.orderPrice); tv_moreBtn = itemView.findViewById(R.id.tv_moreBtn); normalBtnlay = itemView.findViewById(R.id.normalButtons); } public void bind(OrderEntity item) { name.setText(item.getName()); price.setText(item.getPrice()); // ===============更多 中按钮=========================== if (item.getExt_buttons() != null && item.getButtons().size() > 0) { // 存在就显示 tv_moreBtn.setVisibility(View.VISIBLE); ActionMorePopWindow orderMorePopWindow = new ActionMorePopWindow( itemView.getContext(), item.getExt_buttons() ); orderMorePopWindow.setOnItemMyListener(new ActionMorePopWindow.OnPopWindowItemListener() { @Override public void OnItemListener(int position, OrderActionBtnEntity orderActionEntity) { performClicker(itemView.getContext(),orderActionEntity, orderActionEntity.getType()); } }); tv_moreBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { orderMorePopWindow.showPopupWindow(tv_moreBtn); } }); } else { tv_moreBtn.setVisibility(View.GONE); } // =============== 普通按钮============== normalBtnlay.removeAllViews(); if (item.getButtons() != null && item.getButtons().size() > 0) { // 存在普通按钮就加入linearLayout normalBtnlay.setVisibility(View.VISIBLE); // 显示 for (int i = 0; i < item.getButtons().size(); i++) { TextView normalBtn = createBtn(itemView.getContext(), item.getButtons().get(i)); normalBtnlay.addView(normalBtn); int finalI = i; normalBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { performClicker(itemView.getContext(),item.getButtons().get(finalI), (Integer) normalBtn.getTag()); } }); } } else { // 不显示 normalBtnlay.setVisibility(View.GONE); } } private TextView createBtn(Context context, OrderActionBtnEntity buttonEntity) { TextView tv = new TextView(context); tv.setText(buttonEntity.getName()); tv.setTag(buttonEntity.getType()); tv.setBackground(context.getResources().getDrawable(R.drawable.order_btn_normal_bg)); frameLayout.LayoutParams layoutParams = new frameLayout.LayoutParams(DensityUtil.INSTANCE.dp2px(75f), DensityUtil.INSTANCE.dp2px(30f)); layoutParams.setMargins(DensityUtil.INSTANCE.dp2px(10f), 0, 0, 0);//4个参数按顺序分别是左上右下 tv.setLayoutParams(layoutParams); tv.setGravity(Gravity.CENTER); tv.setPadding(10, 5, 10, 5); // 设置按钮的文字颜色和边框高亮颜色,不存在就是默认的灰色 GradientDrawable gradientDrawable = (GradientDrawable) tv.getBackground(); gradientDrawable.setStroke(1, Color.parseColor(buttonEntity.getColor()));//设置边框的宽度和颜色 tv.setTextColor(Color.parseColor(buttonEntity.getColor())); return tv; } } private void performClicker(Context context, OrderActionBtnEntity entity, int type) { switch (type) { case MainActivity .DELETE_TYPE: Toast.makeText(context, "点击了按钮:" + entity.getName(), Toast.LENGTH_SHORT).show(); case MainActivity .GO_SHOPPING_CART_TYPE: Toast.makeText(context, "点击了按钮:" + entity.getName(), Toast.LENGTH_SHORT).show(); case MainActivity .MAKE_AN_INVOICE_TYPE: Toast.makeText(context, "点击了按钮:" + entity.getName(), Toast.LENGTH_SHORT).show(); } } }
绘制点9 图片需要注意规则:
1、左上控制拉伸,黑边之外不会拉伸
2 、右下控制内容显示的地方,黑边以为外padding



