问题描述
我为所有已安装的应用程序创建了一个自定义listView,但是我不知道如何添加搜索功能,因为它有点复杂(..my应用程序),有人可以帮助我吗? (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-listView适配器
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,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 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
,它返回ArrayFilter
-此内部类在底部声明。当您调用getFilter().filter(
时,performFiltering
被调用(在单独的线程中)并遍历数据的本地副本(第588行)。它使用values.get(i).toString().toLowerCase()
比较来自数组的对象和传递的String
(实际上是CharSequence
)。因此在您的自定义App
类中重写toString
方法并在其中返回一些可搜索的值,例如
@Override
public String toString(){
return name;
}
这不是最好的方法,因为toString
可以用于许多机制(其Object的基本方法)中,并且在以上toString
实现中,有两个App
具有相同名称,但不同的version
或number
被同一对象威胁的事实,这是不正确的……也许更好的方法是return name+version+number;
,但您仍然拥有{{ 1}}。这就是为什么我建议(在编辑之前在此答案中)使自己的类扩展Drawable
并实现自己的过滤,或者至少使用BaseAdapter
,但重写ArrayAdapter
方法并返回自己的{ {1}}实现比较变量而不是使用getFilter
。然后就不需要重写此类,保持原样。默认情况下,它返回种类的内存地址,因此对于每个新的Filter
实例来说,它都是唯一的,即使使用完全相同的变量创建它也是如此
还在THIS答案中,您可以找到一个很好的示例,如何实现toString