Android基于高德地图实现搜索框的自动输入提示功能
2017-09-25 09:14
1111 查看
最近公司项目中一直在搞地图开发,今天产品经理就给我布置了一些(无法想象)任务,其中一个就是实现地点搜索输入框的自动输入提示功能。拿到任务肯定想讨价还价一番,但是想到以前也写过,就不再负隅顽抗了。
以前在学校的时候实现过类似功能,是使用高德自带的InputtipsListener来实现的,想了解可以看看:文章传送点,这里就不详细介绍了。作为一名头脑发热的开发者,肯定不能安于现状,这里主要介绍其他两种方式 - poi实现和http请求接口实现,不管能不能成功,试了再说,撸起袖子就是干。先看看最终的效果:
做之前先分析一下功能需求,首先输入框中要添加内容清除的icon,当输入框有文字时,需要显示,为空时隐藏;接着,需要实现地址搜索功能并通过listview展示结果;最后需要实现展示搜索历史的功能。好的,那么下面我们来一步步实现。
其实,实现效果中的输入框并不难,只需要三个东西就够了:LinearLayout,EditText,ImageView。直接上代码吧,上了代码你就知道它到底有多简单了:
没错,这里为EditText父容器LinearLayout设置背景,然后EditText设置同样的背景,只不过需要将右边的圆角效果去掉,达到预期效果。也即是说,我们的输入框相当于是LinearLayout,里面包含了edittext和删除图标imageview,来看看drawable的代码吧:
search_view_bg:
search_edit_bg:
ok,这就实现了最终的输入框UI,当然,你可以使用其他方式实现,比如自定义view,第三方开源等等,但我觉得这完全满足我们的需求,而且简单,不是吗?接下来,我们需要通过监听EditText的变化来实现搜索框中删除的变化,代码如下:
代码比较简单,就不解释了,不理解这个方法的可以谷歌一下,我们接着往下看。
用过高德地图api的开发者应该都知道里面有个常用的功能:POI搜索.高德提供了千万级别的 POI(Point of Interest,兴趣点)。在地图表达中,一个 POI 可代表一栋大厦、一家商铺、一处景点等等。通过POI搜索,完成找餐馆、找景点、找厕所等等的功能。如果我们的需求是获取周围兴趣点,那么搜索输入提示只要显示兴趣点就可以了。
下面我们来依次通过两种方法来实现快捷输入提示功能:
POI搜索实现:
话不多说,直接上代码:
注释都比较清楚,大家理解起来应该也不难,具体用法可以参考高德官方文档,可以直接在onTextChangeed()方法中判断是否有内容来调用doSearchQuery()方法即可。
通过实时访问http接口实现:
除了以上方法实现,还可以用高德提供的web端API接口实现功能,详情见高德web服务开发文档。我们可以直接通过请求高德为我们提供的搜索url接口来访问并获取数据,输入提示API服务地址为:
http://restapi.amap.com/v3/assistant/inputtips?
需要我们填充相应的字段,如key,keyword等,具体介绍看官方文档就可以了,大波代码来袭:
通过okhttp请求网络接口有很多大神封装好的工具库,这里我使用的鸿神的okHttpUtils,大家可以根据自己的需要来选择。同时,这里使用了CommonAdapter来作为listview的适配器,同样是鸿神的杰作,如果你对它不熟悉,建议去看一下这篇文章:打造listview万能适配器。其他的就没什么难点了,关键还是靠自己研究和练习一下了。
最后,让我们来看看如何实现展示搜索历史的功能吧。先分析一下需求:首先进入到搜索界面要展示搜索历史列表,然后可以点击列表下方的清空历史来清除数据,接着,当我们搜索地名并选中时,自动存入搜索历史。其实,说到底,就是两个小功能,数据存储和数据展示,下面依次来探讨如何实现。
搜索历史数据的存储:
一般地,我们会将搜索的历史数据保存在本地。常用的两种方式分别为数据库存储和sp(SharedPreference)存储,两种方式都可以实现我们的需求,这里我才用的是数据库,有时间的话大家可以试试sp存储方式。这里不研究数据库的基本用法比较简单,就一笔带过了,直接上代码:
首先是创建数据库:
具体操作:
数据库的操作网上很多教程和文章,这里就不多加解释,主要说一下逻辑吧。首先,我们输入关键词搜索到相应的目标地点后,点击回调中,即插入一条该地名的数据。当然,为了防止重复,我们需要判断一下数据库中是否已经存在该数据。我们刚进入搜索界面的时候,需要查询数据库中所有的数据并展示。
搜索历史数据的展示和删除:
展示的话没什么太大的问题,一般采用listview展示并为item加上点击事件就OK了,主要是要设置好展示数据和刷新数据的逻辑。这里主要提一下如何实现下方”清除搜索历史”的友好展示以及逻辑。
如果有人问你如何快速实现listview下面的button依附效果,你会怎么回答?常见的回答一般有两种:
1.在listview下面放一个button,然后外面套一层ScrollerView
2.使用listview的addFooterView()给其添加底部布局
虽然两种方式很容易想到,但是对于我们这些新手来说,动手实现起来多少有些弯弯绕绕。比如第一种方式,我们需要考虑如何处理嵌套滑动的问题,至于第二种,无非是研究listview之footerview的用法,当然,抛开各自的难点,第二种方式无非更加优雅一些,所以,这里只讨论如何使用该方式实现。
首先看一下footerview的布局:
search_history_item:
listview添加footerview比较简单,只通过简单的两行代码:
便可以实现,但是footerview的点击事件如何获取呢?很多人说直接用onItenClickListener()呀,但是,大家可以通过log或者toast看看,点击footerview是否真的响应了。答案是 - 并没有。我们应该尽量避免在onITemClickListener回调方法中实现footerview点击事件,因为position并没有变化,上限依旧是原来的adapter.getCount()。我们可以先禁止footerview在item中的点击响应,即addFooterView()方法第三个参数设为false,然后给footerView单独设置点击事件:
到这里,我们就完整实现了地图的搜索功能了,虽然实现的方式比较简单,但还是学到一些东西的。后面有时间会将该部分功能做个demo单独分享出来。另外大家如果有什么问题和优化建议,欢迎留言反馈,不胜感激��。
最后,请教一下大家mac如何录制gif呢,为什么我用licecap录制出来的是黑屏呢(⊙﹏⊙).
以前在学校的时候实现过类似功能,是使用高德自带的InputtipsListener来实现的,想了解可以看看:文章传送点,这里就不详细介绍了。作为一名头脑发热的开发者,肯定不能安于现状,这里主要介绍其他两种方式 - poi实现和http请求接口实现,不管能不能成功,试了再说,撸起袖子就是干。先看看最终的效果:
做之前先分析一下功能需求,首先输入框中要添加内容清除的icon,当输入框有文字时,需要显示,为空时隐藏;接着,需要实现地址搜索功能并通过listview展示结果;最后需要实现展示搜索历史的功能。好的,那么下面我们来一步步实现。
其实,实现效果中的输入框并不难,只需要三个东西就够了:LinearLayout,EditText,ImageView。直接上代码吧,上了代码你就知道它到底有多简单了:
<LinearLayout android:layout_width="wrap_content" android:layout_height="36dp" android:layout_weight="1" android:layout_marginLeft="20dp" android:background="@drawable/search_view_bg" android:orientation="horizontal" android:gravity="center_vertical"> <EditText android:id="@+id/search_edit_text" android:layout_width="wrap_content" android:layout_height="36dp" android:hint="@string/input_cross_location" android:textColorHint="#9B9B9B" android:textSize="12sp" android:maxLines="1" android:layout_weight="1" android:paddingBottom="10dp" android:paddingTop="10dp" android:paddingLeft="10dp" android:background="@drawable/search_edit_bg" android:drawableLeft="@mipmap/icon_edit_search" android:drawablePadding="16dp"/> <ImageView android:id="@+id/search_edit_delete" android:layout_width="12dp" android:layout_height="12dp" android:layout_marginLeft="5dp" android:layout_marginRight="8dp" android:visibility="gone" android:src="@mipmap/iocn_search_cancel"/> </LinearLayout>
没错,这里为EditText父容器LinearLayout设置背景,然后EditText设置同样的背景,只不过需要将右边的圆角效果去掉,达到预期效果。也即是说,我们的输入框相当于是LinearLayout,里面包含了edittext和删除图标imageview,来看看drawable的代码吧:
search_view_bg:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_window_focused="false"> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <!--<solid android:color="#F4F4F4" />--> <corners android:radius="3dp"/> <solid android:color="#F3F3F3"/> <!--<stroke android:color="#ffececec" android:width="1dp"/>--> </shape> </item> <item android:state_window_focused="true"> <shape> <corners android:radius="3dp"/> <!--<stroke android:color="#ececec" android:width="1dp" />--> <solid android:color="#F3F3F3"/> <!--<solid android:color="#F4F4F4" />--> </shape> </item> </selector>
search_edit_bg:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_window_focused="false"> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <!--<solid android:color="#F4F4F4" />--> <corners android:topLeftRadius="3dp" android:bottomLeftRadius="3dp"/> <solid android:color="#F3F3F3"/> <!--<stroke android:color="#ffececec" android:width="1dp"/>--> </shape> </item> <item android:state_window_focused="true"> <shape> <corners android:topLeftRadius="3dp" android:bottomLeftRadius="3dp"/> <!--<stroke android:color="#ececec" android:width="1dp" />--> <solid android:color="#F3F3F3"/> <!--<solid android:color="#F4F4F4" />--> </shape> </item> </selector>
ok,这就实现了最终的输入框UI,当然,你可以使用其他方式实现,比如自定义view,第三方开源等等,但我觉得这完全满足我们的需求,而且简单,不是吗?接下来,我们需要通过监听EditText的变化来实现搜索框中删除的变化,代码如下:
@Bind(R.id.search_edit_text) EditText inputText; @Bind(R.id.search_edit_delete) ImageView buttonDelete; ...... buttonDelete.setOnClickListener(this); inputText.addTextChangedListener(this); ...... @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { if(charSequence!=null){ buttonDelete.setVisibility(View.VISIBLE); }else { buttonDelete.setVisibility(View.GONE); } } @Override public void afterTextChanged(Editable editable) { }
代码比较简单,就不解释了,不理解这个方法的可以谷歌一下,我们接着往下看。
用过高德地图api的开发者应该都知道里面有个常用的功能:POI搜索.高德提供了千万级别的 POI(Point of Interest,兴趣点)。在地图表达中,一个 POI 可代表一栋大厦、一家商铺、一处景点等等。通过POI搜索,完成找餐馆、找景点、找厕所等等的功能。如果我们的需求是获取周围兴趣点,那么搜索输入提示只要显示兴趣点就可以了。
下面我们来依次通过两种方法来实现快捷输入提示功能:
POI搜索实现:
话不多说,直接上代码:
//方法一:使用poi搜索接口方法 private PoiResult poiResult; // poi返回的结果 private int currentPage = 0;// 当前页面,从0开始计数 private PoiSearch.Query query;// Poi查询条件类 private LatLonPoint latLonPoint; private PoiSearch poiSearch; private List<PoiItem> poiItems;// poi数据 private String keyWord; private CommonAdapter adapter; private final int ADDRESS_LOCATION_GET = 3242; private String POI_SEARCH_TYPE = "汽车服务|汽车销售|" + "//汽车维修|摩托车服务|餐饮服务|购物服务|生活服务|体育休闲服务|医疗保健服务|" + "//住宿服务|风景名胜|商务住宅|政府机构及社会团体|科教文化服务|交通设施服务|" + "//金融保险服务|公司企业|道路附属设施|地名地址信息|公共设施"; ...... /** * 开始进行poi搜索 */ protected void doSearchQuery() { latLonPoint = new LatLonPoint(MyApplication.mapLocation.getLatitude(), MyApplication.mapLocation.getLongitude());// 116.472995,39.993743 keyWord = inputText.getText().toString().trim(); currentPage = 0; //keyWord表示搜索字符串, //第二个参数表示POI搜索类型,二者选填其一,选用POI搜索类型时建议填写类型代码,码表可以参考下方(而非文字) //cityCode表示POI搜索区域,可以是城市编码也可以是城市名称,也可以传空字符串,空字符串代表全国在全国范围内进行搜索 query = new PoiSearch.Query(keyWord, POI_SEARCH_TYPE, ""); query.setPageSize(30);// 设置每页最多返回多少条poiItem query.setPageNum(currentPage);// 设置查第一页 if (latLonPoint != null) { poiSearch = new PoiSearch(this, query); poiSearch.setOnPoiSearchListener(this); poiSearch.setBound(new PoiSearch.SearchBound(latLonPoint, 3000, true));//设置搜索范围 poiSearch.searchPOIAsyn();// 异步搜索 } } ...... @Override public void onPoiSearched(PoiResult result, int code) { //DialogUtils.dismissProgressDialog(); if (code == AMapException.CODE_AMAP_SUCCESS) { if (result != null && result.getQuery() != null) {// 搜索poi的结果 loge("搜索的code为===="+code+", result数量=="+result.getPois().size()); if (result.getQuery().equals(query)) {// 是否是同一次搜索 poiResult = result; loge("搜索的code为===="+code+", result数量=="+poiResult.getPois().size()); List<SuggestionCity> suggestionCities = poiResult.getSearchSuggestionCitys();// 当搜索不到poiitem数据时,会返回含有搜索关键字的城市信息 if (poiItems != null && poiItems.size() > 0) { poiItems.clear(); if (adapter != null) { adapter.notifyDataSetChanged(); } } poiItems = poiResult.getPois();// 取得第一页的poiitem数据,页数从数字0开始 //通过listview显示搜索结果的操作省略 ...... } } else { loge("没有搜索结果"); toast(getString(R.string.search_no_result)); empty_view.setText(getString(R.string.search_no_result)); } } else { loge("搜索出现错误"); toast(getString(R.string.search_error)); empty_view.setText(getString(R.string.search_error)); } } @Override public void onPoiItemSearched(PoiItem poiItem, int i) { }
注释都比较清楚,大家理解起来应该也不难,具体用法可以参考高德官方文档,可以直接在onTextChangeed()方法中判断是否有内容来调用doSearchQuery()方法即可。
通过实时访问http接口实现:
除了以上方法实现,还可以用高德提供的web端API接口实现功能,详情见高德web服务开发文档。我们可以直接通过请求高德为我们提供的搜索url接口来访问并获取数据,输入提示API服务地址为:
http://restapi.amap.com/v3/assistant/inputtips?
需要我们填充相应的字段,如key,keyword等,具体介绍看官方文档就可以了,大波代码来袭:
//方法二:使用http请求返回搜索结果 private List<POISearchResultBean.Tips> tipsList; private POISearchResultBean resultBean; private String locationString; private String lon; private String lat; private final int SEARCH_OK = 3266; @Bind(R.id.search_result_listview) ListView resultListView; ....... private MapSerchActivity.MyWeakReferenceHandler handler = new MapSerchActivity.MyWeakReferenceHandler(this) { @Override public void handleMessage(Message msg, Activity weakReferenceActivity) { if (msg.what == ADDRESS_LOCATION_GET) { if (tipsList != null && tipsList.size() > 0) { if (adapter == null && resultListView != null) { //wrong resultListView.setAdapter(adapter = new CommonAdapter<POISearchResultBean.Tips>(SearchAddressActivity.this, tipsList, R.layout.search_result_item) { @Override public void convert(ViewHolder helper, final POISearchResultBean.Tips item) { helper.setText(R.id.search_result_item_address_name, item.getName()); helper.setText(R.id.search_result_item_address_detail, item.getDistrict()+item.getAddress()); helper.getView(R.id.search_result_item_address_layout).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { loge("点击了item"); toast(item.getName()); boolean hasData = hasData(item.getName()); if (!hasData) { insertData(item.getName()); //queryData(""); } locationString = item.getLocation(); lon = locationString.substring(0,locationString.indexOf(",")); lat = locationString.substring(locationString.indexOf(",")+1,locationString.length()); loge("经纬度信息为==="+lon+","+lat); Intent intent = new Intent(); intent.putExtra("location_lon",lon); intent.putExtra("location_lat",lat); setResult(SEARCH_OK, intent); finish(); } }); } }); } else { adapter = null; resultListView.setAdapter(adapter = new CommonAdapter<POISearchResultBean.Tips>(SearchAddressActivity.this, tipsList, R.layout.search_result_item) { @Override public void convert(ViewHolder helper, final POISearchResultBean.Tips item) { helper.setText(R.id.search_result_item_address_name, item.getName()); helper.setText(R.id.search_result_item_address_detail, item.getDistrict()+item.getAddress()); helper.getView(R.id.search_result_item_address_layout).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // loge("点击了item"); loge("点击了item"); toast(item.getName()); boolean hasData = hasData(item.getName()); if (!hasData) { insertData(item.getName()); //queryData(""); } locationString = item.getLocation(); lon = locationString.substring(0,locationString.indexOf(",")); lat = locationString.substring(locationString.indexOf(",")+1,locationString.length()); loge("经纬度信息为==="+lon+"====="+lat); Intent intent = new Intent(); intent.putExtra("location_lon",lon); intent.putExtra("location_lat",lat); setResult(SEARCH_OK, intent); finish(); } }); } }); } } } } }; ....... /** * by moos on 2017/09/11 * func:http请求返回关键词搜索结果 * 请求路径范例:http://restapi.amap.com/v3/assistant/inputtips?key=您的key&keywords=肯德基&types=050301&location=116.481488,39.990464&city=北京&datatype=all */ private void searchAddressByHttp(String keyWord){ //DialogUtils.createProgressDialog(SearchAddressActivity.this,"Searching..."); OkHttpUtils .get() .url(HttpAPI.AMAP_POI_SEARCH_URL + "key="+Const.amap_poi_search_key+"&keywords="+keyWord) .build() .execute(new StringCallback() { @Override public void onError(Call call, Exception e, int id) { loge("获取http poi搜索结果失败=" + e.getMessage()); //DialogUtils.dismissProgressDialog(); Toast.makeText(SearchAddressActivity.this, getString(R.string.act_qr_code_fail), Toast.LENGTH_LONG).show(); } @Override public void onResponse(String response, int id) { Logger.e("获取http poi搜索结果 =" + response); resultBean = JSONObject.parseObject(response, POISearchResultBean.class); if (resultBean.getStatus()==1) { //处理和显示搜索数据列表 if (tipsList != null && tipsList.size() > 0) { tipsList.clear(); if (adapter != null) { adapter.notifyDataSetChanged(); } } tipsList = resultBean.getTips(); Message message = Message.obtain(handler); message.what = ADDRESS_LOCATION_GET; handler.sendMessage(message); } else { toast("搜索失败,请重新尝试"); } } }); }
通过okhttp请求网络接口有很多大神封装好的工具库,这里我使用的鸿神的okHttpUtils,大家可以根据自己的需要来选择。同时,这里使用了CommonAdapter来作为listview的适配器,同样是鸿神的杰作,如果你对它不熟悉,建议去看一下这篇文章:打造listview万能适配器。其他的就没什么难点了,关键还是靠自己研究和练习一下了。
最后,让我们来看看如何实现展示搜索历史的功能吧。先分析一下需求:首先进入到搜索界面要展示搜索历史列表,然后可以点击列表下方的清空历史来清除数据,接着,当我们搜索地名并选中时,自动存入搜索历史。其实,说到底,就是两个小功能,数据存储和数据展示,下面依次来探讨如何实现。
搜索历史数据的存储:
一般地,我们会将搜索的历史数据保存在本地。常用的两种方式分别为数据库存储和sp(SharedPreference)存储,两种方式都可以实现我们的需求,这里我才用的是数据库,有时间的话大家可以试试sp存储方式。这里不研究数据库的基本用法比较简单,就一笔带过了,直接上代码:
首先是创建数据库:
/** * Created by moos on 17/9/11. */ public class SearchHistorySQLiteHelper extends SQLiteOpenHelper { private static String name = "search.db"; private static Integer version = 1; public SearchHistorySQLiteHelper(Context context) { super(context, name, null, version); } @Override public void onCreate(SQLiteDatabase sqLiteDatabase) { sqLiteDatabase.execSQL("create table history(id integer primary key autoincrement,name varchar(200))"); } @Override public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) { } }
具体操作:
//历史搜索功能 private SearchHistorySQLiteHelper helper = new SearchHistorySQLiteHelper(this); private SQLiteDatabase db; private BaseAdapter baseAdapter; @Bind(R.id.search_history_listview) ListView search_history_listView; @Bind(R.id.search_history_view) LinearLayout search_history_view; ...... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_search_address); ButterKnife.bind(this); initView(); } private void initView(){ buttonCancel.setOnClickListener(this); buttonDelete.setOnClickListener(this); inputText.addTextChangedListener(this); search_history_listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { loge("点击了第"+position+"个搜索历史item"); TextView textView = (TextView) view.findViewById(R.id.search_history_item_address_name); String name = textView.getText().toString(); inputText.setText(name); Toast.makeText(SearchAddressActivity.this, name, Toast.LENGTH_SHORT).show(); } }); // 第一次进入查询所有的历史记录 queryData(""); } ...... //采用本地数据库存储 /** * 插入数据 */ private void insertData(String tempName) { db = helper.getWritableDatabase(); db.execSQL("insert into history(name) values('" + tempName + "')"); db.close(); } /** * 模糊查询数据 */ private void queryData(String tempName) { Cursor cursor = helper.getReadableDatabase().rawQuery( "select id as _id,name from history where name like '%" + tempName + "%' order by id desc ", null); // 创建adapter适配器对象 baseAdapter = new SimpleCursorAdapter(this, R.layout.search_history_item, cursor, new String[] { "name" }, new int[] { R.id.search_history_item_address_name }, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); //添加footerView View footerView = LayoutInflater.from(this).inflate(R.layout.delete_search_history_bt,null); search_history_listView.addFooterView(footerView,null,false); footerView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { deleteData(); toast("清除成功"); } }); // 设置适配器 search_history_listView.setAdapter(baseAdapter); baseAdapter.notifyDataSetChanged(); if(baseAdapter.getCount()==0){ //无历史搜索记录 search_history_view.setVisibility(View.GONE); } } /** * 检查数据库中是否已经有该条记录 */ private boolean hasData(String tempName) { Cursor cursor = helper.getReadableDatabase().rawQuery( "select id as _id,name from history where name =?", new String[]{tempName}); //判断是否有下一个 return cursor.moveToNext(); } /** * 清空数据 */ private void deleteData() { db = helper.getWritableDatabase(); db.execSQL("delete from history"); db.close(); loge("搜索历史数据删除成功"); queryData(""); }
数据库的操作网上很多教程和文章,这里就不多加解释,主要说一下逻辑吧。首先,我们输入关键词搜索到相应的目标地点后,点击回调中,即插入一条该地名的数据。当然,为了防止重复,我们需要判断一下数据库中是否已经存在该数据。我们刚进入搜索界面的时候,需要查询数据库中所有的数据并展示。
搜索历史数据的展示和删除:
展示的话没什么太大的问题,一般采用listview展示并为item加上点击事件就OK了,主要是要设置好展示数据和刷新数据的逻辑。这里主要提一下如何实现下方”清除搜索历史”的友好展示以及逻辑。
如果有人问你如何快速实现listview下面的button依附效果,你会怎么回答?常见的回答一般有两种:
1.在listview下面放一个button,然后外面套一层ScrollerView
2.使用listview的addFooterView()给其添加底部布局
虽然两种方式很容易想到,但是对于我们这些新手来说,动手实现起来多少有些弯弯绕绕。比如第一种方式,我们需要考虑如何处理嵌套滑动的问题,至于第二种,无非是研究listview之footerview的用法,当然,抛开各自的难点,第二种方式无非更加优雅一些,所以,这里只讨论如何使用该方式实现。
首先看一下footerview的布局:
search_history_item:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal"> <TextView android:id="@+id/item_search_history_delete" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="15dp" android:gravity="center" android:text="清楚搜索历史" android:textSize="12sp" android:layout_marginBottom="15dp" android:textColor="#828282"/> </LinearLayout>
listview添加footerview比较简单,只通过简单的两行代码:
//添加footerView View footerView = LayoutInflater.from(this).inflate(R.layout.delete_search_history_bt,null); search_history_listView.addFooterView(footerView,null,false);
便可以实现,但是footerview的点击事件如何获取呢?很多人说直接用onItenClickListener()呀,但是,大家可以通过log或者toast看看,点击footerview是否真的响应了。答案是 - 并没有。我们应该尽量避免在onITemClickListener回调方法中实现footerview点击事件,因为position并没有变化,上限依旧是原来的adapter.getCount()。我们可以先禁止footerview在item中的点击响应,即addFooterView()方法第三个参数设为false,然后给footerView单独设置点击事件:
footerView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { deleteData(); toast("清除成功"); } });
到这里,我们就完整实现了地图的搜索功能了,虽然实现的方式比较简单,但还是学到一些东西的。后面有时间会将该部分功能做个demo单独分享出来。另外大家如果有什么问题和优化建议,欢迎留言反馈,不胜感激��。
最后,请教一下大家mac如何录制gif呢,为什么我用licecap录制出来的是黑屏呢(⊙﹏⊙).
相关文章推荐
- 使用FlexBox和Json实现类似ComboBox(类似Google的输入提示和自动)功能-基于JQuery-ASP.NET
- jQuery+PHP+Mysql实现输入自动完成提示的功能
- 用jQuery的ajax的功能实现输入自动提示的功能
- AJAX实现文本框输入自动提示功能
- android中自动提示、补全、连接的功能实现
- 实现搜索框输入时 提示相近词的功能
- jquery ajax 实现搜索框自动提示功能
- jquery 实现邮箱输入自动提示功能:(二)
- 输入自动提示与补全功能的设计与实现
- 基于javascript实现的搜索时自动提示功能
- jQuery+PHP+Mysql实现输入自动完成提示的功能
- Qt 控件 实现 QComboBox输入自动提示功能(仿Google搜索提示)
- android实现自动提示功能
- php+jquery 实现输入自动完成提示的功能
- 搜索框根据输入自动提示--js实现
- 使用python代码实现三叉搜索树高效率”自动输入提示”功能
- jquery 实现邮箱输入自动提示功能:(一)
- jquery 实现邮箱输入自动提示功能
- 输入自动提示与补全功能的设计与实现
- 基于 jQuery+PHP+Mysql实现输入自动完成提示