android ——ListView

一年好景君须记,最是橙黄橘绿时。这篇文章主要讲述android ——ListView相关的知识,希望能为你提供帮助。
谷歌官方文档的介绍:https://developer.android.com/reference/android/widget/ListView.html
显示可垂直滚动的视图集合,其中每个视图都立即位于列表中的上一个视图的下方。 为了更现代化,更灵活和更有效地显示列表,请使用RecyclerView。。。
现在活动布局中加入ListView:

< ?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="match_parent" android:orientation="vertical"> < ListView android:id="@+id/list_view" android:layout_width="match_parent" android:layout_height="match_parent"/> < /LinearLayout>

这里做一个定制的列表,就是自己定制列表中的布局。新建一个hero_item.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="match_parent" android:orientation="horizontal"> < ImageView android:id="@+id/hero_img" android:layout_width="wrap_content" android:layout_height="wrap_content" /> < TextView android:id="@+id/hero_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:textSize="20sp"/> < /LinearLayout>

再然后是这次想要使用的数据,http://ow.blizzard.cn/heroes/,数据来自暴雪的守望先锋官网的英雄介绍页面
android ——ListView

文章图片

旁边的html代码中< img src="https://www.songbingjia.com/android/..." class="portrait"> 是英雄头像的url,< /span> < span class="portrait-title"> 末日铁拳< /span> < /span> 是英雄的名字。
所以新建一个H
public class Hero {private String imageUrl; private String name; public Hero(String imageUrl, String name) { this.imageUrl = imageUrl; this.name = name; }public String getUrl() { return imageUrl; }public void setUrl(String url) { this.imageUrl = url; }public String getName() { return name; }public void setName(String name) { this.name = name; } }

然后就是ListView的Adapter,新建一个HeroAdapter.class,这个Adapter继承自ArrayAdapter,并将泛型指定为Hero
public class HeroAdapter extends ArrayAdapter< Hero> {private int resourceId; public HeroAdapter(Context context, int textViewResourceId, List< Hero> objects){ super(context,textViewResourceId,objects); resourceId = textViewResourceId; }@NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { Hero hero = getItem(position); View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false); ImageView heroImg = (ImageView) view.findViewById(R.id.hero_img); TextView heroName = (TextView) view.findViewById(R.id.hero_name); Glide.with(getContext()).load(hero.getUrl()).into(heroImg); heroName.setText(hero.getName()); return view; } }

HeroAdapter重写了父类的构造函数,可以获得上下文,ListView的子布局的id和数据,然后重写getView()方法,这个方法会在每个子项被滚动到屏幕时调用,在getItem()中根据position获得当前的Hero实例,然后使用LayoutInflater来为这个子项加载布局,再然后设置布局中的ImageView 和TextView,最后返回布局。
最后活动中的代码
public class MainActivity extends AppCompatActivity {private List< Hero> heroList = new ArrayList< > (); private Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final ListView listView = (ListView) findViewById(R.id.list_view); initHeroes(); handler = new Handler(){ @Override public void handleMessage(Message msg) { if(msg.what == 1){ HeroAdapter adapter = new HeroAdapter(MainActivity.this, R.layout.hero_item, heroList); listView.setAdapter(adapter); } } }; }//读取数据 private void initHeroes(){ String weatherUrl = "http://ow.blizzard.cn/heroes/"; HttpUtil.sendOkHttpRequest(weatherUrl, new Callback() { @Override public void onResponse(Call call, Response response) throws IOException { final String responseText = response.body().string(); new Thread(new Runnable() { @Override public void run() { Document doc = Jsoup.parse(responseText); //将String类型的html转换为Document Elements elements1 = doc.select(".portrait"); //读取图片url Elements elements2 = doc.select(".portrait-title"); //读取英雄名字 for (int j = 0; j < elements1.size(); j++) { Hero hero = new Hero(elements1.get(j).attr("src"), elements2.get(j).text()); heroList.add(hero); } Message msg = new Message(); msg.what = 1; handler.sendMessage(msg); } }).start(); }@Override public void onFailure(Call call, IOException e) { e.printStackTrace(); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this, "数据获取失败", Toast.LENGTH_SHORT).show(); } }); } }); } }

创建一个HeroAdapter,传入上下文,子布局和数据,再将这个适配器传递给ListView就好了
android ——ListView

文章图片

  代码优化:
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { Hero hero = getItem(position); View view; ViewHolder viewholder; //检验之前是否已经加载好布局 if(convertView != null) { view = convertView; viewholder = (ViewHolder) view.getTag(); }else { view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false); viewholder = new ViewHolder(); viewholder.heroImg = (ImageView) view.findViewById(R.id.hero_img); viewholder.heroName = (TextView) view.findViewById(R.id.hero_name); view.setTag(viewholder); } Glide.with(getContext()).load(hero.getUrl()).into(viewholder.heroImg); viewholder.heroName.setText(hero.getName()); return view; }classViewHolder{ ImageView heroImg; TextView heroName; } }

根据如果之前加载过的布局就重用之前的,不再使用LayoutInflater去加载布局,然后还把之前获取的布局控件的id也保存了下来。这样做的话。。像这次这样简单的布局和数据就有点加载得快过头了。。。
 
ListView的点击事件
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final ListView listView = (ListView) findViewById(R.id.list_view); .... listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView< ?> adapterView, View view, int i, long l) { Hero hero = heroList.get(i); Toast.makeText(MainActivity.this,hero.getName(),Toast.LENGTH_SHORT).show(); } }); }

【android ——ListView】 

    推荐阅读