高仿 微信、支付宝 选择银行卡效果(PopupWindow实现)
尊敬的各位兄弟姐妹们,韩小呆同学终于逮到时间(忙里偷闲,花样嘬死更确切),为大家带来这个效果实现方式。额,日后我争取一周给大家带来一个好玩的效果,或者是实用的效果或者...总之是开发中实用的东西。
下面步入正题,我们先看一下支付宝和微信的效果吧:
微信效果 支付宝效果
韩小呆同学实现的效果
目测,没差多少,额,不要在意细节。韩小呆是程序员界的穷x。下面开始撸码:
1、搭建界面
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rl_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#005B9E"
android:focusable="true"
android:focusableInTouchMode="true"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_alignParentStart="true"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="用户名:"
android:textColor="#ffffff"
android:textSize="18sp" />
<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="10dp"
android:layout_toEndOf="@+id/tv_name"
android:paddingStart="10dp"
android:paddingEnd="1dp"
android:singleLine="true"
android:textColor="#fff"
android:textSize="14sp"
tools:text="韩小呆" />
<TextView
android:id="@+id/tv_bank"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_below="@+id/tv_name"
android:layout_alignParentStart="true"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="银行名:"
android:textColor="#fff"
android:textSize="18sp" />
<EditText
android:id="@+id/et_bank"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_below="@+id/tv_name"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:layout_toEndOf="@+id/tv_bank"
android:paddingStart="10dp"
android:paddingEnd="1dp"
android:singleLine="true"
android:textColor="#fff"
android:textSize="14sp"
tools:text="招商银行" />
<TextView
android:id="@+id/tv_bank_num"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_below="@+id/tv_bank"
android:layout_alignParentStart="true"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="账户号:"
android:textColor="#fff"
android:textSize="18sp" />
<EditText
android:id="@+id/et_bank_num"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_below="@+id/tv_bank"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:layout_toEndOf="@+id/tv_bank_num"
android:inputType="number"
android:paddingStart="10dp"
android:paddingEnd="1dp"
android:singleLine="true"
android:textColor="#fff"
android:textSize="14sp"
tools:text="6227000132080872008" />
<TextView
android:id="@+id/tv_phone"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_below="@+id/tv_bank_num"
android:layout_alignParentStart="true"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="手机号:"
android:textColor="#fff"
android:textSize="18sp" />
<EditText
android:id="@+id/et_phone"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_below="@+id/tv_bank_num"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:layout_toEndOf="@+id/tv_name"
android:inputType="number"
android:paddingStart="10dp"
android:paddingEnd="1dp"
android:singleLine="true"
android:textColor="#fff"
android:textSize="14sp"
tools:text="15210990809" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_phone"
android:layout_marginTop="20dp"
android:orientation="horizontal"
android:padding="20dp">
<Button
android:id="@+id/btn_add"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:layout_weight="1"
android:background="#1EA362"
android:text="add"
android:textAllCaps="false"
android:textColor="#ffffff"
android:textSize="18sp" />
<Button
android:id="@+id/btn_show"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:background="#1EA362"
android:text="show"
android:textAllCaps="false"
android:textColor="#ffffff"
android:textSize="18sp" />
</LinearLayout>
</RelativeLayout>
Activity 的界面搭建很简单,就是 一个添加银行卡的过程,和展示 popupWindow 的相关按钮;搭建完成是这个样子的:
Activity 界面
popupWindow 的界面更加简单一个 RecycleView 就行了,如下:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fl_pop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#50000000">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="300dp"
android:background="#07182A"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:text="选择到账银行卡"
android:textColor="#00FFF6"
android:textSize="16sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:text="平台7个工作日内线下打款,请注意到账时间"
android:textColor="#00CCFF"
android:textSize="12sp" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_alignParentBottom="true"
android:layout_marginTop="10dp"
android:background="#0C889B" />
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/rlv_pop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#07182A" />
</LinearLayout>
</FrameLayout>
弹出框效果
item 的效果就不放了,太简单了,浪费篇幅。
2、适配器逻辑
package com.hxd.bankcardpop;
import android.annotation.SuppressLint;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.RadioButton;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Content:
* Actor:韩小呆 ヾ(✿゚▽゚)ノ
* Time: 2019/01/05 22:09
* Update:
* Time:
*/
public class PopAdapter extends RecyclerView.Adapter<PopAdapter.MyViewHolder> {
private Context mContext;
private List<CardBean> cards;
private OnItemClickListener mOnItemClickListener;
private HashMap<Integer, Boolean> map;
@SuppressLint("UseSparseArrays")
PopAdapter(Context mContext) {
this.mContext = mContext;
map = new HashMap<>();
cards = new ArrayList<>();
}
public void setData(List<CardBean> cardBeans) {
this.cards.clear();
this.cards.addAll(cardBeans);
map.clear();
for (int i = 0; i < this.cards.size(); i++) {
map.put(i, false);
}
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
return new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_pop, viewGroup, false));
}
@Override
public void onBindViewHolder(@NonNull final MyViewHolder myViewHolder, final int i) {
CardBean card = cards.get(i);
myViewHolder.tvName.setText(card.getCard_bank());
if (card.getId() == 0) {
myViewHolder.rbSelect.setVisibility(View.INVISIBLE);
myViewHolder.ibDel.setVisibility(View.INVISIBLE);
} else {
myViewHolder.rbSelect.setVisibility(View.VISIBLE);
myViewHolder.ibDel.setVisibility(View.VISIBLE);
}
myViewHolder.rbSelect.setChecked(map.get(i));
myViewHolder.ibDel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int pos = myViewHolder.getLayoutPosition();
mOnItemClickListener.onDelClick(myViewHolder.ibDel, pos);
}
});
myViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int pos = myViewHolder.getLayoutPosition();
mOnItemClickListener.onSelectClick(myViewHolder.itemView, pos);
myViewHolder.rbSelect.setChecked(true);
map.put(pos, map.get(pos));
notifyDataSetChanged();
singleSelect(pos);
}
});
}
//设置单选
private void singleSelect(int pos) {
Set<Map.Entry<Integer, Boolean>> entries = map.entrySet();
for (Map.Entry<Integer, Boolean> entry : entries) {
entry.setValue(false);
}
map.put(pos, true);
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return cards.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
private TextView tvName;
private ImageButton ibDel;
private RadioButton rbSelect;
MyViewHolder(@NonNull View itemView) {
super(itemView);
tvName = itemView.findViewById(R.id.tv_card_name);
ibDel = itemView.findViewById(R.id.ib_del);
rbSelect = itemView.findViewById(R.id.cb_card);
}
}
public interface OnItemClickListener {
void onDelClick(View view, int pos);
void onSelectClick(View view, int pos);
}
void setOnItemClickListener(OnItemClickListener onItemClickListener) {
mOnItemClickListener = onItemClickListener;
}
}
这里面值得一说的是 RecycleView 的单选处理,对于高手 很简单,一个 map 解决了。但是对于像楼主这样的菜鸟就得反复琢磨了。
其实也很简单啦,在初始化Adapter 的时候,初始化一个map。当传入数据的时候,首先将 map内的数据清空,然后向内put进去,数据的位置和全部置位为false。 当选择某个item 的时候 将被选中的 item 的 RadioButton 变为已选,遍历map,将其余的item的选择状态均变为false。
如果看源码 ,请看上部分代码的 map 相关。
这里有一个细节需要注意一下,RecycleView 的item 内的 最好不要用 gone来隐藏看见,任意丢控件, 控件的隐藏和展示是成对出现的。
3、Activity 相关逻辑
package com.hxd.bankcardpop;
import android.annotation.SuppressLint;
import android.graphics.drawable.ColorDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener, PopAdapter.OnItemClickListener {
private EditText etName;
private EditText etBank;
private EditText etBankNum;
private EditText etPhone;
private Button btnShow;
private Button btnAdd;
private RelativeLayout rlMain;
private PopupWindow popCard;
private PopAdapter adapter;
private View view;
private List<CardBean> cardBeans;
private int tag = 5;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rlMain = findViewById(R.id.rl_main);
etName = findViewById(R.id.et_name);
etBank = findViewById(R.id.et_bank);
etBankNum = findViewById(R.id.et_bank_num);
etPhone = findViewById(R.id.et_phone);
btnShow = findViewById(R.id.btn_show);
btnAdd = findViewById(R.id.btn_add);
adapter = new PopAdapter(this);
adapter.setOnItemClickListener(this);
btnAdd.setOnClickListener(this);
btnShow.setOnClickListener(this);
cardBeans = new ArrayList<>();
for (int i = 1; i < 5; i++) {
cardBeans.add(new CardBean(i, "a" + i, "韩小呆" + i, "招商银行" + i, "622700013209087200" + i, "1383146022" + i));
}
cardBeans.add(new CardBean(0, "0", "0", "使用新卡提现", "0", "0"));
initPopView();
}
@SuppressLint("InflateParams")
private void initPopView() {
view = getLayoutInflater().inflate(R.layout.pop_card, null, false);
FrameLayout flPop = view.findViewById(R.id.fl_pop);
RecyclerView rlvPop = view.findViewById(R.id.rlv_pop);
rlvPop.setLayoutManager(new LinearLayoutManager(this));
rlvPop.setAdapter(adapter);
flPop.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.btn_add:
addData();
break;
case R.id.btn_show:
showPop();
break;
case R.id.fl_pop:
popCard.dismiss();
break;
}
}
private void addData() {
tag++;
String username = etName.getText().toString().trim();
String bank = etBank.getText().toString().trim();
String bankNum = etBankNum.getText().toString().trim();
String phone = etPhone.getText().toString().trim();
if (TextUtils.isEmpty(bank)) {
Toast.makeText(this, "必须输入银行名称!", Toast.LENGTH_SHORT).show();
} else {
cardBeans.remove(cardBeans.size() - 1);
cardBeans.add(new CardBean(tag, "" + tag, username, bank + tag, bankNum, phone));
cardBeans.add(new CardBean(0, "0", "0", "使用新卡提现", "0", "0"));
Toast.makeText(this, "添加成功!", Toast.LENGTH_LONG).show();
}
}
private void showPop() {
if (popCard == null) {
popCard = new PopupWindow(view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, true);
}
popCard.setBackgroundDrawable(new ColorDrawable());
popCard.showAtLocation(rlMain, Gravity.CENTER, 0, 0);
adapter.setData(cardBeans);
adapter.notifyDataSetChanged();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (popCard != null) {
popCard.dismiss();
}
}
@Override
public void onDelClick(View view, int pos) {
cardBeans.remove(pos);
Toast.makeText(this, "删除第 " + (pos + 1) + " 条数据成功", Toast.LENGTH_LONG).show();
popCard.dismiss();
}
@Override
public void onSelectClick(View view, int pos) {
Toast.makeText(this, "选择第 " + (pos + 1) + " 条数据成功", Toast.LENGTH_LONG).show();
// popCard.dismiss();
}
}
这里有几个细节需要注意一下:
1、PopupWindow内的view 最好只初始化一次,笔者看好多文章都是反复进行初始化,笔者不知道手机累不累性能咋样;
2、PopupWindow 也最好只初始化一次;
3、需要程序员自己整理服务器返还的数据,游戏时候服务器返回的json不是我们需要的哦。这是我们必备技能。
下面来运行一下,看看效果哦:
运行效果
最后献上demo 地址: BankCardPop