Perform/Add 自定义 ListView 的搜索功能
Perform/Add search functionality to a custom ListView
我创建了所有已安装应用程序的自定义列表视图,但我不知道如何添加搜索功能,因为它有点复杂(..我的应用程序)有人可以帮我吗?
(picture of the app )
App.java - 应用程序构造函数
public class App {
private int number;
private String name;
private String version;
private Drawable drawable;
public App(int number, String name, String version, Drawable drawable){
this.number = number;
this.name = name;
this.version = version;
this.drawable = drawable;
}
//Getters & Setters...
}
AppAdapter.java - 列表视图适配器
public class AppAdapter extends ArrayAdapter<App> {
Context context;
List<App> objects;
public AppAdapter(Context context, int resources, int textViewResources, List<App> objects){
super(context, resources, textViewResources, objects);
this.context = context;
this.objects = objects;
}
public View getView(int position, View convertView, ViewGroup parent){
LayoutInflater layoutInflater = ((Activity)context).getLayoutInflater();
View view = layoutInflater.inflate(R.layout.custom_card,parent,false);
TextView tvName = (TextView)view.findViewById(R.id.tvName);
TextView tvVersion = (TextView)view.findViewById(R.id.tvVersion);
TextView tvNumber = (TextView)view.findViewById(R.id.tvNumber);
ImageView ivImage = (ImageView)view.findViewById(R.id.ivImage);
App current = objects.get(position);
tvName.setText(String.valueOf(current.getName()));
tvVersion.setText(String.valueOf(current.getVersion()));
tvNumber.setText(String.valueOf(current.getNumber()));
ivImage.setImageDrawable(current.getDrawable());
return view;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
ArrayList<App> appList;
ListView lv;
AppAdapter appAdapter;
App lastSelected;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditText etSearch = findViewById(R.id.etSearch);
PackageManager packageManager = getPackageManager();
List<PackageInfo> mApps = packageManager.getInstalledPackages(0);
//array strings to all packages, names and version
final String[] arrPackages = new String[mApps.size()];
final String[] arrVersion = new String[mApps.size()];
String[] arrName = new String[mApps.size()];
//array of Drawables for icons...
Drawable[] arrIcons = new Drawable[mApps.size()];
App[] arrApps = new App[mApps.size()];
appList = new ArrayList<>();
//reading all app's packages and version to the arrays
for (int i = 0; i < mApps.size(); i++){
arrVersion[i] = mApps.get(i).versionName;
arrPackages[i] = mApps.get(i).packageName;
}
for (int i = 0; i < mApps.size(); i++){
try {//getting app's names from theres packages
arrName[i] = (String) packageManager.getApplicationLabel(packageManager.getApplicationInfo(arrPackages[i], PackageManager.GET_META_DATA));
} catch (PackageManager.NameNotFoundException e) {
arrName[i] = "Unknown";
}
try {//same as names for icons
arrIcons[i] = packageManager.getApplicationIcon(arrPackages[i]);
} catch (PackageManager.NameNotFoundException e) {
arrIcons[i] = getDrawable(R.drawable.placeholder);
}
arrApps[i] = new App(i + 1, "Name: "+arrName[i], "Version: "+arrVersion[i], arrIcons[i]);
appList.add(arrApps[i]);
}
//on item click open app
appAdapter = new AppAdapter(this,0,0,appList);
lv = findViewById(R.id.lv);
lv.setAdapter(appAdapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
lastSelected = appAdapter.getItem(position);
Intent launchIntent = getPackageManager().getLaunchIntentForPackage(arrPackages[position]);
if (launchIntent != null) {
startActivity(launchIntent);//null pointer check in case package name was not found
}
}
});
//(trying to..) Add Text Change Listener to EditText
etSearch.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Call back the Adapter with current character to Filter
MainActivity.this.appAdapter.getFilter().filter(s.toString());
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
}
(当我尝试搜索某些内容时,它什么也没给出...)
交换这条线
App current = objects.get(position);
至此
App current = (App) getItem(position);
您不需要将 List<App> objects;
保留在您的适配器中,它在构造函数 super
调用(最后一个参数)中传递并为您保存在引擎盖下。查看 ArrayAdapter source - 传递的 ArrayList
保留为 mObjects
并在某些方法中进一步使用,例如getPosition
、getCount
和 getItem
ArrayAdapter
已经 implements Filterable
,所以有一个覆盖方法 getFilter
,其中 returns ArrayFilter
- 这个内部 class 是在底部声明。当您调用 getFilter().filter(
时,performFiltering
会被调用(在单独的线程中)并遍历数据的本地副本(第 588 行)。它使用 values.get(i).toString().toLowerCase()
将数组中的对象与传递的 String
(实际上是 CharSequence
)进行比较。所以在你的自定义 App
class 覆盖 toString
方法和 return 中有一些可搜索的值,例如
@Override
public String toString(){
return name;
}
这不是最好的方法,因为 toString
可以用在很多机制中(它的 Object 的基本方法)和上面的 toString
实现两个 App
s 具有相同的名称,但不同的 version
或 number
被威胁为同一对象,这是不正确的......也许更好的方法是 return name+version+number;
,但你仍然有Drawable
在那里。这就是为什么我建议(在编辑之前的这个答案中)制作自己的 class extends BaseAdapter
并实现自己的过滤或至少使用 ArrayAdapter
,但覆盖 getFilter
方法和return 你自己的 Filter
实现比较变量而不是使用 toString
。然后不需要覆盖这个class,保持原样。默认情况下,它 returns kind-of 内存地址,因此它对于每个新的 App
实例都是唯一的,即使是使用完全相同的变量创建时也是如此
也在 THIS 答案中,您可以找到如何实现 Filter
的好例子
我创建了所有已安装应用程序的自定义列表视图,但我不知道如何添加搜索功能,因为它有点复杂(..我的应用程序)有人可以帮我吗? (picture of the app )
App.java - 应用程序构造函数
public class App {
private int number;
private String name;
private String version;
private Drawable drawable;
public App(int number, String name, String version, Drawable drawable){
this.number = number;
this.name = name;
this.version = version;
this.drawable = drawable;
}
//Getters & Setters...
}
AppAdapter.java - 列表视图适配器
public class AppAdapter extends ArrayAdapter<App> {
Context context;
List<App> objects;
public AppAdapter(Context context, int resources, int textViewResources, List<App> objects){
super(context, resources, textViewResources, objects);
this.context = context;
this.objects = objects;
}
public View getView(int position, View convertView, ViewGroup parent){
LayoutInflater layoutInflater = ((Activity)context).getLayoutInflater();
View view = layoutInflater.inflate(R.layout.custom_card,parent,false);
TextView tvName = (TextView)view.findViewById(R.id.tvName);
TextView tvVersion = (TextView)view.findViewById(R.id.tvVersion);
TextView tvNumber = (TextView)view.findViewById(R.id.tvNumber);
ImageView ivImage = (ImageView)view.findViewById(R.id.ivImage);
App current = objects.get(position);
tvName.setText(String.valueOf(current.getName()));
tvVersion.setText(String.valueOf(current.getVersion()));
tvNumber.setText(String.valueOf(current.getNumber()));
ivImage.setImageDrawable(current.getDrawable());
return view;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
ArrayList<App> appList;
ListView lv;
AppAdapter appAdapter;
App lastSelected;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditText etSearch = findViewById(R.id.etSearch);
PackageManager packageManager = getPackageManager();
List<PackageInfo> mApps = packageManager.getInstalledPackages(0);
//array strings to all packages, names and version
final String[] arrPackages = new String[mApps.size()];
final String[] arrVersion = new String[mApps.size()];
String[] arrName = new String[mApps.size()];
//array of Drawables for icons...
Drawable[] arrIcons = new Drawable[mApps.size()];
App[] arrApps = new App[mApps.size()];
appList = new ArrayList<>();
//reading all app's packages and version to the arrays
for (int i = 0; i < mApps.size(); i++){
arrVersion[i] = mApps.get(i).versionName;
arrPackages[i] = mApps.get(i).packageName;
}
for (int i = 0; i < mApps.size(); i++){
try {//getting app's names from theres packages
arrName[i] = (String) packageManager.getApplicationLabel(packageManager.getApplicationInfo(arrPackages[i], PackageManager.GET_META_DATA));
} catch (PackageManager.NameNotFoundException e) {
arrName[i] = "Unknown";
}
try {//same as names for icons
arrIcons[i] = packageManager.getApplicationIcon(arrPackages[i]);
} catch (PackageManager.NameNotFoundException e) {
arrIcons[i] = getDrawable(R.drawable.placeholder);
}
arrApps[i] = new App(i + 1, "Name: "+arrName[i], "Version: "+arrVersion[i], arrIcons[i]);
appList.add(arrApps[i]);
}
//on item click open app
appAdapter = new AppAdapter(this,0,0,appList);
lv = findViewById(R.id.lv);
lv.setAdapter(appAdapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
lastSelected = appAdapter.getItem(position);
Intent launchIntent = getPackageManager().getLaunchIntentForPackage(arrPackages[position]);
if (launchIntent != null) {
startActivity(launchIntent);//null pointer check in case package name was not found
}
}
});
//(trying to..) Add Text Change Listener to EditText
etSearch.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Call back the Adapter with current character to Filter
MainActivity.this.appAdapter.getFilter().filter(s.toString());
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
}
(当我尝试搜索某些内容时,它什么也没给出...)
交换这条线
App current = objects.get(position);
至此
App current = (App) getItem(position);
您不需要将 List<App> objects;
保留在您的适配器中,它在构造函数 super
调用(最后一个参数)中传递并为您保存在引擎盖下。查看 ArrayAdapter source - 传递的 ArrayList
保留为 mObjects
并在某些方法中进一步使用,例如getPosition
、getCount
和 getItem
ArrayAdapter
已经 implements Filterable
,所以有一个覆盖方法 getFilter
,其中 returns ArrayFilter
- 这个内部 class 是在底部声明。当您调用 getFilter().filter(
时,performFiltering
会被调用(在单独的线程中)并遍历数据的本地副本(第 588 行)。它使用 values.get(i).toString().toLowerCase()
将数组中的对象与传递的 String
(实际上是 CharSequence
)进行比较。所以在你的自定义 App
class 覆盖 toString
方法和 return 中有一些可搜索的值,例如
@Override
public String toString(){
return name;
}
这不是最好的方法,因为 toString
可以用在很多机制中(它的 Object 的基本方法)和上面的 toString
实现两个 App
s 具有相同的名称,但不同的 version
或 number
被威胁为同一对象,这是不正确的......也许更好的方法是 return name+version+number;
,但你仍然有Drawable
在那里。这就是为什么我建议(在编辑之前的这个答案中)制作自己的 class extends BaseAdapter
并实现自己的过滤或至少使用 ArrayAdapter
,但覆盖 getFilter
方法和return 你自己的 Filter
实现比较变量而不是使用 toString
。然后不需要覆盖这个class,保持原样。默认情况下,它 returns kind-of 内存地址,因此它对于每个新的 App
实例都是唯一的,即使是使用完全相同的变量创建时也是如此
也在 THIS 答案中,您可以找到如何实现 Filter