0
点赞
收藏
分享

微信扫一扫

为RecyclerView添加点击事件、长按事件

宁静的猫 2023-02-01 阅读 155


一、准备工作

  1. 保存App信息的bean

public class AppInfo {

public String name; // 应用名
public String packageName; // 应用包名
public Drawable icon; // 应用图标

public boolean isRom; // 应用的安装位置
public boolean isUser; // 系统还是用户应用
}

  1. 获取手机所有App的信息
    可以了解获取系统信息的相关API

public class AppInfoProvider {

/**
* 获取已安装应用
*/
public static ArrayList<AppInfo> getIntalledApps(Context ctx) {
PackageManager pm = ctx.getPackageManager();
List<PackageInfo> installedPackages = pm.getInstalledPackages(0); // 获取所有已安装的包

ArrayList<AppInfo> list = new ArrayList<AppInfo>();
for (PackageInfo packageInfo : installedPackages) {
AppInfo info = new AppInfo();
String packageName = packageInfo.packageName;
ApplicationInfo applicationInfo = packageInfo.applicationInfo; // 应用信息
String name = applicationInfo.loadLabel(pm).toString();
Drawable icon = applicationInfo.loadIcon(pm);

int uid = applicationInfo.uid; // 当前应用的标识

info.packageName = packageName;
info.name = name + uid;
info.icon = icon;

// 状态机, 通过0/1状态来表示是否具备某些属性和功能
int flags = applicationInfo.flags; // 获取应用标记
if ((flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == ApplicationInfo.FLAG_EXTERNAL_STORAGE) {
// 安装在sd
info.isRom = false;
} else {
// 安装在手机内存
info.isRom = true;
}

if ((flags & ApplicationInfo.FLAG_SYSTEM) == ApplicationInfo.FLAG_SYSTEM) {
// 系统应用
info.isUser = false;
} else {
// 用户应用
info.isUser = true;
}

list.add(info);
}

return list;
}
}

  1. activity_main

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

</LinearLayout>

  1. 展示App信息的条目布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp">

<ImageView
android:id="@+id/iv_icon"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:src="@mipmap/ic_launcher"/>

<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="2dp"
android:layout_toRightOf="@+id/iv_icon"
android:singleLine="true"
android:text="名称"
android:textColor="#000"
android:textSize="18sp"/>

<TextView
android:id="@+id/tv_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/iv_icon"
android:layout_alignLeft="@+id/tv_name"
android:layout_marginTop="3dp"
android:text="手机内存"
android:textColor="#000"
android:textSize="16sp"/>

</RelativeLayout>

  1. 头布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<TextView
android:id="@+id/tv_head"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#9e9e9e"
android:padding="5dp"
android:text="用户应用(0)"
android:textColor="#fff"
android:textSize="16sp"/>

</LinearLayout>

二、适配器(★)

事件的添加需要我们手动进行,分别添加点击和长按接口,接口中添加抽象方法,参数为当前布局对象和点击的条目的位置,然后绑定到当前实现的View.OnClickListener接口的​onClick()​方法中,具体过程请看本篇最后第四章

public class AppAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements View.OnClickListener, View.OnLongClickListener {

public static final int TYPE_HEAD = 0;
public static final int TYPE_APPS = 1;

// 这里数据源有两个(系统应用列表和用户应用列表)
private ArrayList<AppInfo> mUserList; // 所有已安装用户应用的集合
private ArrayList<AppInfo> mSystemList; // 所有已安装系统应用的集合

public AppAdapter(ArrayList<AppInfo> userList, ArrayList<AppInfo> systemList) {
mUserList = userList;
mSystemList = systemList;
}

@Override public int getItemViewType(int position) {
if (position == 0 || position == mUserList.size() + 1) {
return TYPE_HEAD;
} else {
return TYPE_APPS;
}
}

@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = null;
RecyclerView.ViewHolder holder = null;

switch (viewType) {
case TYPE_HEAD:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_header, null);
holder = new HeadHolder(view);
break;

case TYPE_APPS:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_appinfo, null);

/**
* 为展示应用信息的布局添加点击和长按事件监听
*/
view.setOnClickListener(this);
view.setOnLongClickListener(this);

holder = new AppsHolder(view);
break;
}

return holder;
}

@Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (getItemViewType(position)) {
case TYPE_HEAD:
if (0 == position) {
((HeadHolder) holder).tvHead.setText("用户应用(" +mUserList.size() + ")");
} else {
((HeadHolder) holder).tvHead.setText("系统应用(" + mSystemList.size() + ")");
}

break;

case TYPE_APPS:
AppInfo info;
if (position < mUserList.size() + 1) {
info = mUserList.get(position - 1); // 从用户应用列表中获取应用信息
} else {
info = mSystemList.get(position - mUserList.size() - 2); // 从系统应用列表中获取应用信息
}

// 设置控件内容
((AppsHolder) holder).tvName.setText(info.name);
((AppsHolder) holder).ivIcon.setImageDrawable(info.icon);

if (info.isRom) {

((AppsHolder) holder).tvLocation.setText("内置存储卡");
} else {
((AppsHolder) holder).tvLocation.setText("外部存储卡");
}

/**
* 将position保存在itemView的Tag中以便点击时获取
*/
holder.itemView.setTag(position);
break;
}
}

@Override public int getItemCount() {
return mUserList.size() + mSystemList.size() + 2; // 加上两条头布局条目
}


/****************************************
* Holder
*/
class HeadHolder extends RecyclerView.ViewHolder {

@BindView(R.id.tv_head) TextView tvHead;

public HeadHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}

class AppsHolder extends RecyclerView.ViewHolder {

@BindView(R.id.tv_name) TextView tvName;
@BindView(R.id.iv_icon) ImageView ivIcon;
@BindView(R.id.tv_location) TextView tvLocation;

public AppsHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}


/****************************************
* Listener
*/
/**
* 手动添加点击事件
*/
interface OnClickListener {
void onClick(View view, int position);
}

private OnClickListener mOnClickListener = null;

public void setOnClickListener(OnClickListener listener) {
mOnClickListener = listener;
}

@Override public void onClick(View view) {
if (null != mOnClickListener) {
mOnClickListener.onClick(view, (int) view.getTag());
}
}

/**
* 手动添加长按事件
*/
interface OnLongClickListener {
void onLongClick(View view, int position);
}
private OnLongClickListener mOnLongClickListener = null;
public void setOnLongClickListener(OnLongClickListener listener) {
mOnLongClickListener = listener;
}
@Override public boolean onLongClick(View view) {
if (null != mOnLongClickListener) {
mOnLongClickListener.onLongClick(view, (int) view.getTag());
}

// 消耗事件,否则长按逻辑执行完成后还会进入点击事件的逻辑处理
return true;
}
}

三、Activity中使用

重点看setAdapter之后的点击和长按事件的具体处理逻辑即可

public class AppsActivity extends AppCompatActivity {

@BindView(R.id.rv) RecyclerView rv;
private AppAdapter mAdapter;

private LinearLayoutManager mLayoutManager;

@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_apps);
ButterKnife.bind(this);

initData(); // 初始化数据

rv.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
rv.setLayoutManager(mLayoutManager);
rv.setItemAnimator(new DefaultItemAnimator());

mAdapter = new AppAdapter(mUserList, mSystemList);
rv.setAdapter(mAdapter);

/**
* 点击和长按事件的具体处理
*/
mAdapter.setOnClickListener(new AppAdapter.OnClickListener() {
@Override public void onClick(View view, int position) {
if (position < mUserList.size() + 1) {
Toast.makeText(AppsActivity.this, mUserList.get(position - 1).name, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(AppsActivity.this, mSystemList.get(position - mUserList.size() - 2).name, Toast.LENGTH_SHORT).show();
}
}
});
mAdapter.setOnLongClickListener(new AppAdapter.OnLongClickListener() {
@Override public void onLongClick(View view, int position) {
if (position < mUserList.size() + 1) {
Toast.makeText(AppsActivity.this, "长按" + mUserList.get(position - 1).name, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(AppsActivity.this, "长按" + mSystemList.get(position - mUserList.size() - 2).name, Toast.LENGTH_SHORT).show();
}
}
});
}


private ArrayList<AppInfo> mList; // 所有已安装应用的集合
private ArrayList<AppInfo> mUserList; // 所有已安装用户应用的集合
private ArrayList<AppInfo> mSystemList; // 所有已安装系统应用的集合

private void initData() {
mList = AppInfoProvider.getIntalledApps(getApplicationContext());

// 区分用户和系统应用,分别放在两个集合中
mUserList = new ArrayList<AppInfo>();
mSystemList = new ArrayList<AppInfo>();
for (AppInfo info : mList) {
if (info.isUser) {
mUserList.add(info);
} else {
mSystemList.add(info);
}
}
}
}

四、点击事件实现过程

  1. 定义点击事件接口
  2. onCreateViewHolder()中为每个条目添加点击事件
  3. onBindViewHolder()中设置被点击条目的position
  4. View.OnClickListener​onClick()​方法中将事件传递给外面的调用者


举报

相关推荐

0 条评论