景点介绍(ListView控件应用)

2024-03-12 16:30

本文主要是介绍景点介绍(ListView控件应用),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 案例概述

此案例主要是对ListView列表控件的使用。当应用中包含多项数据,每项数据结构相同,只是内容不同时,可通过列表显示。对于列表中的内容,可以是显示字符串的TextView,也可以是结构较复杂的包含多个控件的容器。

此案例通过列表显示景点的基本信息,单击列表中的某一项后可以查看该景点的详细信息,且图片会徐徐展开。其中所涉及知识点:

  • 复杂列表框的构建
  • 列表项的事件处理
  • 页面的跳转
  • 数据的传递

程序运行效果如下:

10186693-c4b7774064fd045b.gif
景点介绍.gif

2.1界面分析

从案例中包含两个界面:

  • 一个是用于显示南昌各景点基本信息的主界面;
  • 一个是用于显示单个景点详细信息的界面,单击主界面中的某一项后,可以跳转到对应的详细信息界面。

在主页面中,主要包含两个控件,显示标题的TextView以及显示景点信息的ListView。在ListView中,设置了项与项之间的分割线颜色,以及分割线的大小即android:divider和android:dividerHeight属性。列表中每一项又包含三项信息:景点图片、景点名、景点简介,这三项信息整体放在一个水平的线性布局中,其中又嵌套了一个垂直的线性布局,效果如下图所示。


10186693-3876c07f865f7494.png
item布局结构

2.2 布局文件代码

主界面布局文件: activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/title"android:textSize="24sp"android:background="#ccbbaa"android:textColor="#ffffff"android:padding="10dp"android:gravity="center" /><ListViewandroid:id="@+id/scenery"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="8dp"android:layout_marginRight="8dp"android:divider="#aaaaaa"android:dividerHeight="2dp"android:gravity="center" />
</LinearLayout>

列表每一项的布局:item.xml

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_margin="10dp"android:orientation="horizontal"><ImageViewandroid:id="@+id/image"android:layout_width="100dp"android:layout_height="75dp"android:contentDescription="@string/imgInfo" /><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="10dp"android:orientation="vertical" ><TextViewandroid:id="@+id/name"android:layout_width="match_parent"android:layout_height="wrap_content"android:textColor="#000000"android:textSize="20sp" /><TextViewandroid:id="@+id/brief"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:gravity="left"android:singleLine="true"android:ellipsize="end"android:textColor="#0000ee"android:textSize="12sp" /></LinearLayout>
</LinearLayout>

显示详细信息的布局文件:scenery_show.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollViewxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:background="#ccbbaa"android:orientation="vertical" ><TextViewandroid:id="@+id/title"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:padding="10dp"android:background="#ccbbaa"android:textColor="#ffffff"android:textSize="24sp"/><ImageViewandroid:id="@+id/image"android:layout_width="match_parent"android:layout_height="240dp"android:scaleType="fitXY"android:contentDescription="@string/imgInfo"/><TextViewandroid:id="@+id/content"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="#ffffff"android:textColor="#000000"android:textSize="16sp"android:padding="10dp"/></LinearLayout>
</ScrollView>

3.1 逻辑代码分析

  • ListView介绍

ListView是Android中使用非常广泛的一种控件,它以垂直列表的形式显示所有的列表项。在Android中使用ListView控件与其它控件类似,通常是在布局文件中添加ListView标签,然后在代码中根据ID获取ListView控件,然后即可为其设置数据源,显示数据等。

除此外,在Android中还专门提供了ListActivity,其内部包含了一个ListView,因此只需要让当前的Activity从ListActivity继承即可获得一个ListView,而不需要布局文件。

获取ListView控件后,关键是为其指定数据源,但ListView本身并不能直接与需要显示的数据源关联,需要借助中介Adapter的协助,然后通过setAdapter()方法将Adapter与列表关联起来。

10186693-2a78be2c3dddee6f.png
Adapter层次结构图

Adapter层次结构中比较关键的类就是BaseAdapter类,该类本身是一个抽象类,不能够实例化,开发者只需从该类继承,然后重写里面的抽象方法即可创建自定义Adapter。创建自定义Adapter必须实现如下方法:

  • getView():返回列表中每一项显示的视图,可以是一个结构复杂的布局对应的View,也可以是简单的控件如TextView;
  • getCount():返回列表中项的个数,根据这个值循环填充列表;
  • getItemId():返回指定项的ID;
  • getItem():返回指定项的对象。

其中getView()方法和getCount()方法最为关键,通过getCount()方法即可知道列表中一共有多少项,然后通过getCount()次循环调用getView()方法,获取每一项数据,并将每一项信息添加到ListView中即可形成包含数据的列表。

Android系统中提供了几个比较常见的BaseAdapter子类:

  1. ArrayAdapter适合于列表项中只包含文本情况。
  2. SimpleAdapter适合于列表项结构较为复杂的情况。
  3. CursorAdapter适合于将数据库查询的结果转换成列表的情况。
  • SimpleAdapter介绍

SimpleAdapter是一个简单而实用的Adapter,它可以将静态的数据关联到XML布局文件中的某个View控件上。通常将静态的数据保存在Map对象的集合中,一个Map对象对应列表中一项所包含的所有数据,通过Map对象中的关键字来区分。本例中一个景点包含四部分数据:景点图片、景点名称、景点简介、景点详情,因此Map对象中包含四个关键字,见以下代码清单,所有Map对象的集合即组成了整个数据源。

将每个景点的图片、名称、简介、详情关联起来

    private void init() {// 将每个景点的图片、名称、简介、详情关联起来for (int i = 0; i < imgIds.length; i++) {Map<String, Object> item = new HashMap<String, Object>();item.put("img", imgIds[i]);//添加景点图片IDitem.put("name", names[i]);//添加景点名称item.put("brief", briefs[i]);//添加景点简介item.put("content", contentIds[i]);//添加景点内容list.add(item);//添加景点}}

在Map对象中是根据关键字key来唯一确定数据项中每部分所对应的值,在布局文件中通过id来唯一确定单个控件,因此只需要将Map对象的关键字key与布局文件中的控件的id建立一一对应的关系即可保证数据的一致。

SimpleAdapter类的构造方法:
public SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) {}

使用SimpleAdapter自定义ListView列表项时需传递5个参数:

  • 参数1:Context对象,通常为当前的Activity对象;
  • 参数2:List<? Extends Map <String,?>>集合对象,该集合中包含了列表中需要显示的所有数据,集合中有多少个元素,列表中就有多少项,每一项数据放在一个Map对象中;
  • 参数3:int类型资源ID,表示列表中每一项对应的布局文件的ID;
  • 参数4:String类型数组,即Map对象中部分关键字组成的数组;
  • 参数5:int类型数组,表示每部分数据如何显示,即指定显示的控件,而控件是根据ID来确定的,因此传递的是控件ID形成的数组。

注意:参数4与参数5存在一一对应的关系,根据参数4获取的数据将会在参数5指定的控件中显示,并且控件必须在参数3所指定的布局文件中。

  • ClipDrawable介绍

ClipDrawable表示从某个位图上截取的一个“图片片段”,通过ClipDrawable实现图片徐徐展开效果的原理是:不断重复截取同一张图片,只是每次截取的片段大小不同,最开始时截取的片段很小,然后不断增大,直到截取整个图片,给人眼的感觉就是徐徐展开。

ClipDrawable对象既可以在代码中创建,也可以在xml文件中定义。在XML文件中使用<clip.../>元素作为根元素,主要包含以下几个属性:

  • android:drawable:指定需要截取的图片对象;
  • android:clipOrientation:指定截取方向:水平或者垂直;
  • android:gravity:指定截取的对齐方式:从左到右,从右到左或者从中间向两边等。

直接在代码中创建ClipDrawable对象时, ClipDrawable(Drawable drawable, int gravity, int orientation) 需要传递三个参数:

  • 第一个参数表示需要截取的图片对象;
  • 第二个参数为截取时对齐方式,从左到右还是从右到左等;
  • 第三个参数是截取的方向,水平还是垂直。

使用ClipDrawable对象截取图片时,是通过setLevel(int level)方法来设置截取的区域大小,当level的值为0时,截取的区域为空;当level为10000时,截取的就是整张图片了。本例中是启动一个线程,判断是否截取了整张图片,如果没有则每隔0.05秒发送一次请求,截取图片,每次截取时,使level的值递增400。

3.2 程序代码

MainActivity.java

public class MainActivity extends Activity {private ListView mScenery;// 显示景点信息的列表// 保存每个景点信息的集合private List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();private int[] imgIds = new int[] { R.drawable.tengwangge,R.drawable.badashanren, R.drawable.hanwangfeng,R.drawable.xiangshangongyuan, R.drawable.xishanwanshougong,R.drawable.meiling };//存放景点图片ID的数组private String[] names = new String[] { "滕王阁", "八大山人纪念馆", "罕王峰", "象山森林公园","西山万寿宫", "梅岭" };//存放景点名称的数组private String[] briefs = new String[] { "江南三大名楼之首", "集收藏、陈列、研究、宣传为一体","青山绿水,风景多彩,盛夏气候凉爽", "避暑、休闲、疗养、度假的最佳场所", "江南著名道教宫观和游览胜地","山势嵯峨,层峦叠翠,四时秀色,气候宜人" };//存放景点简单介绍信息的数组private int[] contentIds = new int[] { R.raw.tengwg_info, R.raw.badsr_info,R.raw.hangwf_info, R.raw.xiangsgy_info, R.raw.wansg_info,R.raw.meil_info };//存放景点详细介绍文件ID的数组protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mScenery = (ListView) findViewById(R.id.scenery);init();//执行初始化操作,即将同一个景点的图片、名称、简介、详情关联起来//创建Adapter对象,将数据源与显示的控件关联起来SimpleAdapter adapter = new SimpleAdapter(this, list, R.layout.item,new String[] { "img", "name", "brief" }, new int[] {R.id.image, R.id.name, R.id.brief });mScenery.setAdapter(adapter);//为列表添加列表项单击事件监听器mScenery.setOnItemClickListener(new OnItemClickListener() {//列表项单击事件处理,跳转页面、传递数据public void onItemClick(AdapterView<?> parent, View view,int position, long id) {Intent intent = new Intent();intent.setClass(MainActivity.this, SceneryShowActivity.class);intent.putExtra("name", (String) list.get(position).get("name"));intent.putExtra("image", (Integer) list.get(position).get("img"));intent.putExtra("content",(Integer) list.get(position).get("content"));startActivity(intent);//跳转页面}});}private void init() {// 将每个景点的图片、名称、简介、详情关联起来for (int i = 0; i < imgIds.length; i++) {Map<String, Object> item = new HashMap<String, Object>();item.put("img", imgIds[i]);//添加景点图片IDitem.put("name", names[i]);//添加景点名称item.put("brief", briefs[i]);//添加景点简介item.put("content", contentIds[i]);//添加景点内容list.add(item);//添加景点}}public boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.main, menu);return true;}
}

SceneryShowActivity.xml

public class SceneryShowActivity extends Activity {private TextView title,content;//显示标题和内容的TextViewprivate ImageView imageView;//显示图片的ImageViewprivate ClipDrawable clipDrawable;//用于图片徐徐展开private Handler mHandler;protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.scenery_show);imageView=(ImageView)findViewById(R.id.image);content=(TextView)findViewById(R.id.content);title=(TextView)findViewById(R.id.title);//获取传递过来的数据,标题、图片ID、详情文件IDString titleStr=getIntent().getStringExtra("name");int image=getIntent().getIntExtra("image",R.drawable.tengwangge);int info=getIntent().getIntExtra("content",R.raw.tengwg_info);  title.setText(titleStr);//创建ClipDrawable对象,指定裁剪的图片、方向等clipDrawable = new ClipDrawable(getResources().getDrawable(image), Gravity.CENTER, ClipDrawable.HORIZONTAL);//思考题:从上到下慢慢展开//clipDrawable = new ClipDrawable(getResources().getDrawable(image), Gravity.TOP,ClipDrawable.VERTICAL);imageView.setImageDrawable(clipDrawable);       startThread();//启动线程,开始裁剪//根据文件ID获取输入流InputStream inputStream=getResources().openRawResource(info);       content.setText(getStringFromInputStream(inputStream));mHandler=new Handler(){//创建handler对象public void handleMessage(Message msg) {//创建handler对象clipDrawable.setLevel(clipDrawable.getLevel()+400);//让图片可显示部分不断增大}};      }//从输入流中读取字符串public String getStringFromInputStream(InputStream inputStream){byte[] buffer=new byte[1024];int hasRead=0;//记录读取的字节个数StringBuilder result=new StringBuilder("");try{while((hasRead=inputStream.read(buffer))!=-1){//根据读取的字节构建字符串并添加到已有字符串后面result.append(new String(buffer, 0,hasRead,"GBK"));}}catch (Exception ex){ex.printStackTrace();}return result.toString();}   public void startThread(){clipDrawable.setLevel(0);//设置图片初始不可见new Thread(){//创建线程public void run() {while(clipDrawable.getLevel()<10000){//判断图片是否完全显示try {Thread.sleep(50);  //休眠0.05秒mHandler.sendEmptyMessage(0x11);//发送空消息} catch (Exception e) {e.printStackTrace();}}}}.start();//启动线程}
}

4.1知识扩展

  • raw目录介绍

景点介绍的文字比较多,不宜放代码中,因此将介绍放在TXT文件中,然后在res下创建raw,将这些文件放入raw中。raw文件夹内文件会原封不动存储到设备上,不会被编译成二进制形式,可通过R.raw.XXX引用文件,使用getResource().OpenRawResources(R.raw.XXX)打开输入流,然后即可读取文件内容。该文件夹不可任意创建文件夹。

assets支持任意深度的总目录,这些文件不会生成任何资源标记,必须使用以/assets开始(但不包含它)的相对路径名,需要使用AssetManager类访问,通过文件流的方式进行读取。

10186693-686fc81011c99e49.png
assets、res、res/raw文件夹对比
  • Activity概述

Activity是Android应用中重要组成部分之一,如果把一个Android应用看成是一个网站的话,那么一个Activity就相当于该网站的一个具体网页。Android应用开发的一个重要组成部分就是开发Activity。

Activity是一种应用程序组件,该组件提供了一个屏幕,用户通过与这个屏幕交互可完成一定的功能,例如打电话,拍照,发送邮件或者查看地图等。每一个Activity都提供了一个用于显示它的用户界面的窗口。这个窗口通常会充满整个屏幕,但有可能比这个屏幕更小或者是漂浮在其他窗口之上。

应用程序通常由多个彼此之间松耦合的Activity组成。通常,在一个应用程序中,有且仅有一个Activity被指定为主Activity。当应用程序第一次启动的时候,该Activity会显示给用户。每个Activity都可以启动其它的Activity用于执行不同的操作(功能)。当一个新的Activity启动的时候,先前的那个Activity就会停止,但是系统在堆栈中仍保存该Activity。当一个新的Activity启动时,它将会被压入栈顶,并获得用户焦点。堆栈遵循后进先出的队列原则,因此,当用户使用完当前的Activity并按Back键时,该Activity将从堆栈中取出(并销毁),然后先前的Activity恢复并获取焦点。

创建和配置Activity
创建自己的Activity需要继承Activity基类,在不同的应用场景下,有时也可继承Activity的子类,例如ListActivity、TabActivity。创建一个Activity需要实现一个或多个方法,其中最常见的就是实现onCreate(Bundle status)方法,该方法将会在Activity创建时被回调,该方法调用Activity的setContentView(View view)方法来显示要展示的View。
为了管理应用程序界面中的各个控件,可调用Activity的findViewById(int id)方法来获取程序界面中的组件,接下来即可修改该组件的属性和方法以满足我们的需求。

注意:Android应用要求所有应用程序组件(Activity、Service、ContentProvider、BroadcastReceiver)都必须进行注册。

为<application …/>元素添加<activity…/>子元素即可注册Activity。注册时,主要有以下几个属性:

  • name:指定该Activity的实现类的类名;
  • icon:指定该Activity对应的图标;
  • label:指定该Activity的标签。

配置Activity时通常还可以指定一个或多个<intent-filter…/>元素,该元素用于指定该Activity可响应的条件。

注意:上述配置中,只有name属性是必须的,而其它属性或标签元素都是可选的。

启动Activity
一个Android应用通常都会包含多个Activity,但只有一个Activity会作为程序的入口(当该Android应用运行时将会自动启动并执行该Activity)。而应用中的其他Activity,通常都由入口Activity启动,或由入口Activity启动的Activity启动。
启动其它Activity的方法如下:

  • startActivity(Intent intent):启动其他Activity;
  • startActivityForResult(Intent intent,int requestCode):程序将会得到新启动

Activity的结果(通过重写onActivityResult(…)方法来获取),requestCode参数代表启动Activity的请求码。这个请求码的值由开发者根据业务自行设置,用于标识请求来源。

上面两个方法,都需要传入一个Intent类型的参数,该参数是对你所需要启动的Activity的描述,既可以是一个确切的Activity类,也可以是所需要启动的Activity的一些特征,然后由系统查找符合该特征的Activity。

如果有多个Activity符合该要求时,系统将会以下拉列表的形式列出所有的Activity,然后由用户选择具体启动哪一个,这些Activity既可以是本应用程序的,也可以是其他应用程序的。

关闭Activity

  • finish():结束当前Activity;
  • finishActivity(int requestCode):结束以startActivityForResult(Intent intent,int requestCode)方法启动的Activity。

注意: 大部分情况下,不建议显式调用这些方法关闭Activity。因为Android系统会为我们管理Activity的生命周期,调用这些方法可能会影响用户的预期体验。因此,只有当你不想用户再回到当前Activity的时候才去关闭它。

思考:

案例中图片展开的效果是水平的,从中间开始向两边慢慢展开,可尝试修改代码,使其从上到下慢慢展开。

彩蛋:景点介绍Demo点击下载处~

这篇关于景点介绍(ListView控件应用)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/801862

相关文章

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

zoj3820(树的直径的应用)

题意:在一颗树上找两个点,使得所有点到选择与其更近的一个点的距离的最大值最小。 思路:如果是选择一个点的话,那么点就是直径的中点。现在考虑两个点的情况,先求树的直径,再把直径最中间的边去掉,再求剩下的两个子树中直径的中点。 代码如下: #include <stdio.h>#include <string.h>#include <algorithm>#include <map>#

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}

AI行业应用(不定期更新)

ChatPDF 可以让你上传一个 PDF 文件,然后针对这个 PDF 进行小结和提问。你可以把各种各样你要研究的分析报告交给它,快速获取到想要知道的信息。https://www.chatpdf.com/