转发备注:https://blog.csdn.net/ctianju/article/details/122109664
背景
淘宝,京东等购物类App订单列表都有“更多”着操作,比如删除订单,查看物流等操作;
分析
Android自带的PopWindow组件就能很好的满足,但是还有问题需要分析解决: 1、弹框的方向问题,如果列表滑动到底部需要向上弹,顶部就向下弹; 解决:计算点击“更多”文字的位置,来动态的改变弹出的方向 2、弹框的背景样式; 解决:最简单利用点9图片作为背景 3、订单列表的 item 数据返回问题 解决:和后端沟通,更多操作的按钮就放到一个list,普通的就放到一个list 4、列表按钮太多放不下问题 解决:利用横向滚动的HorizontalScrollView 动态添加按钮进去
显上效果图
先组建PopWindow
1、重写PopupWindow
public class ActionMorePopWindow extends PopupWindow {
private Context context;
private View conentView;
private RecyclerView listView;
private ActionSelectPopularAdapter selectAdapter;
List<OrderActionBtnEntity> 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<OrderActionBtnEntity> 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);
this.setContentView(conentView);
this.setWidth(LinearLayout.LayoutParams.WRAP_CONTENT);
this.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
this.setFocusable(true);
this.setOutsideTouchable(true);
this.update();
ColorDrawable dw = new ColorDrawable(0000000000);
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<OrderActionBtnEntity> 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) {
llParent.setBackground(v.getContext().getDrawable(R.drawable.order_doctor_more_up_bg));
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));
this.showAsDropDown(v, 0- DensityUtil.INSTANCE.dp2px(10), 0);
}
}
}
2、绘制popwindow布局 popwindow.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:id="@+id/llParent"
xmlns:tools="http://schemas.android.com/tools">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/lv_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#f5f5f5"
tools:itemCount="2"
tools:listitem="@layout/pop_item_action"
android:scrollbars="none"
/>
</LinearLayout>
3、绘制popwindow 里面RecyclerView的item布局 pop_item_action.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:gravity="center_horizontal"
android:background="@color/white"
android:orientation="vertical"
android:padding="7dp">
<TextView
android:layout_gravity="left"
android:id="@+id/orderActionTitle"
android:layout_width="wrap_content"
tools:text="删除订单"
android:layout_height="wrap_content"
android:textColor="#ff666666"
android:textSize="12sp" />
</LinearLayout>
4、ActionSelectPopularAdapter
public class ActionSelectPopularAdapter extends RecyclerView.Adapter<ActionSelectPopularAdapter.MoreActionHolder> {
private List<OrderActionBtnEntity> mData = new ArrayList<>();
private Context context;
private OnItemClickerListener onItemClickerListener;
public ActionSelectPopularAdapter(List<OrderActionBtnEntity> 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
组件外部的RecyclerView
1、activity_main.xm
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:background="#F5F5F5"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/mainRvList"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
2、MainActivity 包括构造数据源
class MainActivity : AppCompatActivity() {
private val normalButtonsList = mutableListOf<OrderActionBtnEntity>()
private val normalButtonsList2 = mutableListOf<OrderActionBtnEntity>()
private val normalButtonsList3 = mutableListOf<OrderActionBtnEntity>()
private val moreButtonsList = mutableListOf<OrderActionBtnEntity>()
private val moreButtonsList2 = mutableListOf<OrderActionBtnEntity>()
private val moreButtonsList3 = mutableListOf<OrderActionBtnEntity>()
private val dataList = mutableListOf<OrderEntity>()
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"))
normalButtonsList2.add(OrderActionBtnEntity(DELETE_TYPE, "支付", "#999999"))
normalButtonsList2.add(OrderActionBtnEntity(DELETE_TYPE, "在线咨询", "#999999"))
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"))
moreButtonsList2.add(OrderActionBtnEntity(DELETE_TYPE, "删除订单", "#999999"))
moreButtonsList2.add(OrderActionBtnEntity(MAKE_AN_INVOICE_TYPE, "申请开票", "#999999"))
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
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:background="@drawable/shape_solid_white_radius_4dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
<ImageView
android:id="@+id/orderImg"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@drawable/ic_launcher_background"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/orderName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textSize="16sp"
app:layout_constraintLeft_toRightOf="@+id/orderImg"
app:layout_constraintTop_toTopOf="@+id/orderImg"
tools:text="大保健" />
<TextView
android:id="@+id/orderPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@+id/orderImg"
app:layout_constraintLeft_toRightOf="@+id/orderImg"
tools:text="¥100.0" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
app:layout_constraintTop_toBottomOf="@+id/orderImg">
<TextView
android:id="@+id/tv_moreBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="更多"
android:textColor="#666666"
android:textSize="16sp"
android:visibility="visible" />
<HorizontalScrollView
android:fillViewport="true"
android:scrollbars="none"
android:layout_marginLeft="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/normalButtons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:orientation="horizontal" />
</HorizontalScrollView>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
4、MainRvAdapter ->>>>> RecyclerView.Adapter
public class MainRvAdapter extends RecyclerView.Adapter<MainRvAdapter.MoreActionHolder> {
private List<OrderEntity> mData = new ArrayList<>();
public MainRvAdapter(List<OrderEntity> 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) {
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);
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
|