当前位置: 代码迷 >> Android >> android中利用兑现二级联动的效果
  详细解决方案

android中利用兑现二级联动的效果

热度:65   发布时间:2016-05-01 09:54:37.0
android中利用实现二级联动的效果

按照惯例,首先上一张效果图。

本篇文章实现的效果就是如图中所圈的那样,实现类似于HTML中的二级联动的效果。

对于第一个选项我们读取的是本地xml文件来填充数据的,

对于第二个选项我们读取的是通过中央气象台提供的API返回的xml格式的数据来填充的。

首先是主页面排版,由于我做的是一个天气预报的功能,所以添加了很多与本文无关的控件,在代码注释中写的很清楚,大家可以直接略过。

public class WeatherPage extends RelativeLayout{	private Context parentContext;		/**监听*/	private MyButtonListen mylisten;		/**定义天气对象*/	private GetWeatherService service;		private RelativeLayout toplayout;	private int toplayoutid=100;	private RelativeLayout centerlayout;	private int centerlayoutid=200;	private RelativeLayout footlayout;	private int footlayoutid=300;		/** topView*/	private ImageView dogpetimg;	private TextView titleview;	private ImageButton switchBtn;		/** showweatherView*/	private RelativeLayout showWeather;	private int showWeatherid=201;	private TextView datetext;		/** functionView*/	private LinearLayout functionLayout;	private TextView selectCitytext;	private Spinner selectProvince;	private ArrayAdapter<CharSequence> adapterProvince;	private Map<String,String> provincemap;		private Spinner selectCity;	private Map<Integer,CityWeather> citymap;	private ArrayAdapter<CharSequence> adapterCity;		private ImageButton okBtn;	private ImageButton selectBtn;		/** 本类对象的样式 */	private LayoutParams lp;//准备放入ViewFlipper中,所以暂且准备一下,		public WeatherPage(Context context) {		super(context);		this.parentContext=context;		mylisten=new MyButtonListen();		service=new GetWeatherService();		init();	}	private void init() {		toplayout=new RelativeLayout(parentContext);		toplayout.setId(toplayoutid);		LayoutParams lptoplayout=new LayoutParams(-1,-2);		lptoplayout.setMargins(0, 20, 0, 0);		//添加组件		addTopLayout(lptoplayout);		addView(toplayout,lptoplayout);								centerlayout=new RelativeLayout(parentContext);		centerlayout.setId(centerlayoutid);		LayoutParams lpcenterlayout=new LayoutParams(-1,370);		lpcenterlayout.setMargins(0, 30, 0, 0);		lpcenterlayout.addRule(RelativeLayout.BELOW,toplayoutid);		//添加组件		addCenterLayout(lpcenterlayout);		addView(centerlayout,lpcenterlayout);						footlayout=new RelativeLayout(parentContext);		footlayout.setBackgroundColor(Color.RED);		footlayout.setId(footlayoutid);		LayoutParams lpfootlayout=new LayoutParams(-1,-2);		lpfootlayout.setMargins(20, 10, 20, 0);		//添加组件		addFootLayout(lpfootlayout);		lpfootlayout.addRule(RelativeLayout.BELOW,centerlayoutid);		addView(footlayout,lpfootlayout);			}		public LayoutParams getLp() {		this.lp=new LayoutParams(-1,-1);		return lp;	}		public void addTopLayout(LayoutParams lp){		dogpetimg=new ImageView(parentContext);		LayoutParams lpdogpetimg=new LayoutParams(60,60);		lpdogpetimg.addRule(RelativeLayout.ALIGN_PARENT_LEFT);		dogpetimg.setBackgroundResource(R.drawable.dogsmall);		lpdogpetimg.setMargins(10, 0, 0, 0);				titleview=new TextView(parentContext);		titleview.setText("天气预报");		titleview.setTextColor(Color.BLUE);		LayoutParams lptitleview=new LayoutParams(-2,-2);		lptitleview.addRule(RelativeLayout.CENTER_HORIZONTAL);				switchBtn=new ImageButton(parentContext);		//先进行判断,判断原来的开关状态,然后再添加背景图片,标记位设置在helper类中。		switchBtn.setBackgroundResource(R.drawable.start);		LayoutParams lpswitchBtn=new LayoutParams(40,40);		lpswitchBtn.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);		lpswitchBtn.setMargins(0, 20, 50, 0);		//添加监听		switchBtn.setOnClickListener(mylisten);		toplayout.addView(dogpetimg,lpdogpetimg);		toplayout.addView(titleview, lptitleview);		toplayout.addView(switchBtn,lpswitchBtn);			}	public void addCenterLayout(LayoutParams lp) {		showWeather=new RelativeLayout(parentContext);		showWeather.setId(showWeatherid);		LayoutParams lpshowWeather=new LayoutParams(400,300);		lpshowWeather.addRule(RelativeLayout.CENTER_HORIZONTAL);		showWeather.setBackgroundColor(Color.CYAN);				datetext=new TextView(parentContext);		LayoutParams lpdatetext=new LayoutParams(400,-2);		lpdatetext.addRule(RelativeLayout.CENTER_HORIZONTAL);		lpdatetext.addRule(RelativeLayout.BELOW,showWeatherid);		lpdatetext.setMargins(20, 20, 20, 0);//		datetext.setBackgroundColor(Color.LTGRAY);		datetext.setText(TimeHelper.getDateInChina());		datetext.setGravity(Gravity.CENTER_HORIZONTAL);				centerlayout.addView(showWeather, lpshowWeather);		centerlayout.addView(datetext, lpdatetext);	}	public void addFootLayout(LayoutParams lp) {				functionLayout=new LinearLayout(parentContext);		functionLayout.setId(301);//		functionLayout.setBackgroundColor(Color.YELLOW);		LayoutParams lpfunctionLayout=new LayoutParams(-2,-2);		lpfunctionLayout.addRule(RelativeLayout.ALIGN_PARENT_TOP);		lpfunctionLayout.addRule(RelativeLayout.CENTER_HORIZONTAL);		lpfunctionLayout.setMargins(10, 0, 0, 0);				//添加显示文字		selectCitytext=new TextView(parentContext);		selectCitytext.setText("请设置:");				//添加选择省		selectProvince=new Spinner(parentContext);		selectProvince.setPrompt("请选择省份");		//获取省份Map<序列号,省份对象>		provincemap=service.getProvinceMap();		String[] provinceData=service.getProvinceArray(provincemap);		//定义下拉列表适配器,用于填充内容		adapterProvince=null;		adapterProvince=new ArrayAdapter<CharSequence>(parentContext,android.R.layout.simple_spinner_item,provinceData);		//设置列表显示风格		adapterProvince.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);		selectProvince.setAdapter(adapterProvince);		selectProvince.setOnItemSelectedListener(new MyOnItemSelectedListen());				//添加选择市		selectCity=new Spinner(parentContext);		selectCity.setPrompt("请选择城市");		//定义下拉列表适配器,用于填充内容		adapterCity=null;		//设置列表显示风格		selectCity.setAdapter(adapterCity);				functionLayout.addView(selectCitytext);		functionLayout.addView(selectProvince);		functionLayout.addView(selectCity);				okBtn=new ImageButton(parentContext);		okBtn.setBackgroundResource(R.drawable.okbtn);//给绑定按钮添加背景图片		LayoutParams lpokBtn=new LayoutParams(-2,-2);		lpokBtn.setMargins(20, 20, 0, 0);		lpokBtn.addRule(RelativeLayout.ALIGN_PARENT_LEFT);		lpokBtn.addRule(RelativeLayout.BELOW,301);		//添加监听		okBtn.setOnClickListener(mylisten);				selectBtn=new ImageButton(parentContext);		selectBtn.setBackgroundResource(R.drawable.selectbn);//给查询按钮添加背景图片		LayoutParams lpselectBtn=new LayoutParams(-2,-2);		lpselectBtn.setMargins(0, 20, 20, 0);		lpselectBtn.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);		lpselectBtn.addRule(RelativeLayout.BELOW,301);		//添加监听		selectBtn.setOnClickListener(mylisten);				footlayout.addView(functionLayout,lpfunctionLayout);		footlayout.addView(okBtn, lpokBtn);		footlayout.addView(selectBtn, lpselectBtn);	}	/**	 * 监听各种按钮的点击事件	 * @author Administrator	 */	class MyButtonListen implements OnClickListener{		@Override		public void onClick(View v) {			// TODO Auto-generated method stub			if(v==switchBtn){				//关闭外显示功能				System.out.println("点击外显示开关");				//换色				switchBtn.setBackgroundResource(R.drawable.end);			}else if(v==okBtn){				//确定,对城市进行保存。写入小型数据库				System.out.println("点击保存开关");							}else if(v==selectBtn){				//确定,对城市进行查询,不保存				System.out.println("点击查询开关");			}else{								Log.e("tag", "问题,输入的值不对");			}		}	}	/**	 * 监听第一个选项的选择,当地一个选项框被选择数据的时候出发该类中的事件	 * @author Administrator	 */	class MyOnItemSelectedListen implements OnItemSelectedListener{		@Override		public void onItemSelected(AdapterView<?> item, View view,				int position, long arg3) {						String provincename = item.getAdapter().getItem(position).toString();			System.out.println(provincename);			String pinyin = provincemap.get(provincename);			Map<String, String> cityIdMap = service.getCityMap(pinyin);			String[] cityArray = service.getCityArray(cityIdMap);						adapterCity=new ArrayAdapter<CharSequence>(parentContext,android.R.layout.simple_spinner_item,cityArray);			//设置列表显示风格			adapterCity.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);			selectCity.setAdapter(adapterCity);		}		@Override		public void onNothingSelected(AdapterView<?> arg0) {			// TODO Auto-generated method stub					}	}}

完成了这些代码,已经基本可以实现骨架的二级联动了。

我这里第一级的连动使用的是读取本地xml文件,

第二级的联动使用的读取API,所以专门建立了一个service类来处理这些事件:

public class GetWeatherService {		private GetWeatherDao dao;		public GetWeatherService() {		dao=new GetWeatherDao();	}		/**	 * 获取城市气象信息的流程	 * @param province	 * @param selectcity	 * @return	 */	public CityWeather getWeatherDay(String province,String selectcity){		//首先,获取所有省份名和拼音的map		Map<String, String> provincemap = getProvinceMap();		//根据所有的省份名 获取 所需要的省份名拼音		String provincexml = provincemap.get(province);		if(provincexml==null){			//有问题,省份不存在			return null;		}		//其次,输入值省份名拼音,获取指定市的城市气象id		Map<String, String> citymap = getCityMap(provincexml);				if(citymap==null){			//有问题,城市不存在			return null;		}				String cityid = citymap.get(selectcity);				//根据id获取城市的json数据,并且解析该数据返回城市未来七天气象信息		CityWeather cityWeather = getCityWeather(cityid);		if(cityWeather==null){			//有问题,解析不正确			return null;		}		return cityWeather;	}		/**	 * 获取所有省份名和拼音的map	 */	public Map<String, String> getProvinceMap() {		Map<String, String> proMap = new HashMap<String, String>();		String res = "";		try {			InputStream in = Helper.getHelper().getContext().getResources()					.getAssets().open("province.xml");			InputStream is = IOHelper.fromInputStreamToInputStreamInCharset(in,"utf-8");//			int length = in.available();//			byte[] buffer = new byte[length];//			in.read(buffer);//			res = EncodingUtils.getString(buffer, "UTF-8");//			InputStream is = IOHelper.fromStringToIputStream(res);			SAXReader sr = new SAXReader();// 获取读取xml的对象。			Document document = sr.read(is);			Element root = document.getRootElement();			List<?> elementlist = root.elements("city");			for (Object obj : elementlist) {				Element row = (Element) obj;				String quName = row.attribute("quName").getText();				String pyName = row.attribute("pyName").getText();				proMap.put(quName, pyName);			}		} catch (Exception e) {			Log.e("tag", "读取配置失败");			e.printStackTrace();		}		return proMap;	}		/**	 * 获取指定省份的城市列表	 */	public Map<String, String> getCityMap(String provincename) {		InputStream cityXml = dao.getCityXml(provincename);				Map<String,String> citymap=new HashMap<String,String>();		try {			SAXReader sr = new SAXReader();// 获取读取xml的对象。			Document document = sr.read(cityXml);			Element root = document.getRootElement();			List<?> elementlist = root.elements("city");			for (Object obj : elementlist) {				Element row = (Element) obj;				String cityname = row.attribute("cityname").getText();				String cityid =row.attribute("url").getText();				citymap.put(cityname,cityid);			}		} catch (Exception e) {			e.printStackTrace();			Log.e("tag", "问题"+e.toString());			return null;		}		return citymap;	}		/**	 * 根据指定的城市气象id获取该城市未来七天的天气信息	 */	public CityWeather getCityWeather(String cityid) {		 CityWeather cityWeather=null;		String weatherJson = dao.getWeatherJson(cityid);		weatherJson="["+weatherJson+"]";		try {		// 对json数组进行循环,一般应该只返回一个。		JSONTokener jsonParser = new JSONTokener(weatherJson);		JSONObject object = (JSONObject) jsonParser.nextValue();		// 接下来的就是JSON对象的操作了		JSONObject weatherday = object.getJSONObject("weatherinfo");		cityWeather = new CityWeather();		String city = weatherday.get("city").toString();		String city_en = weatherday.get("city_en").toString();		String date_y = weatherday.get("date_y").toString();		String week = weatherday.get("week").toString();		String temp1 = weatherday.get("temp1").toString();// 今天温度		String temp2 = weatherday.get("temp2").toString();// 明天温度		String temp3 = weatherday.get("temp3").toString();// 后天温度		String weather1 = weatherday.get("weather1").toString();// 今天温度		String weather2 = weatherday.get("weather2").toString();// 明天温度		String weather3 = weatherday.get("weather3").toString();// 后天温度		cityWeather.setCityname(city);		cityWeather.setCity_en(city_en);		cityWeather.setCityid(cityid);		cityWeather.setDate_y(date_y);		cityWeather.setWeek(week);		cityWeather.setTempToday(temp1);		cityWeather.setTempTommorrow(temp2);		cityWeather.setTempAt(temp3);		cityWeather.setWeatherToday(weather1);		cityWeather.setWeatherTommorrow(weather2);		cityWeather.setWeatherAt(weather3);		} catch (Exception e) {			// TODO: handle exception			return null;		}		return cityWeather;	}	/**	 * 返回省名称的数组	 * @param map	 * @return	 */	public String[] getProvinceArray(Map<String, String> map){		String[] provinceArray=new String[map.size()];		int i=0;		for(String key:map.keySet()){			provinceArray[i++]=key;		}		return provinceArray;	}		public String[] getCityArray(Map<String, String> map){		String[] cityArray=new String[map.size()];		int k=0;		for(String key:map.keySet()){			cityArray[k++]=key;		}		return cityArray;	}}

程序中经常涉及到io流的处理,所以为了方法处理,专门写了一个工具类,为了便于大家调试,也附上代码:

public class IOHelper {	/**	 * 输入InputStream流,返回字符串文字。	 * @param is	 * @return	 */	public static String fromIputStreamToString(InputStream is){		ByteArrayOutputStream baos = new ByteArrayOutputStream();		int i = -1;		try {			while ((i = is.read()) != -1) {				baos.write(i);			}		} catch (IOException e) {			// TODO Auto-generated catch block			e.printStackTrace();		}		return baos.toString();	}		/**	 * 输入InputStream流和文件地址,返回成功与否。	 * @param is	 * @return	 */	public static boolean fromIputStreamToFile(InputStream is,String outfilepath){		byte[] b=new byte[1024];		FileOutputStream fos=null;		try {			fos=new FileOutputStream(new File(outfilepath));			while((is.read(b, 0, 1024))!=-1){				fos.write(b);			}			fos.flush();		} catch (IOException e) {			// TODO Auto-generated catch block			e.printStackTrace();			return false;		}finally{			try {				fos.close();			} catch (IOException e) {				// TODO Auto-generated catch block				e.printStackTrace();			}		}		return true;	}	/**	 * 输入文件地址,返回inputStream流。	 * @param is	 * @return	 */	public static InputStream fromFileToIputStream(String infilepath){		FileInputStream fis=null;		try {			fis=new FileInputStream(new File(infilepath));		} catch (IOException e) {			// TODO Auto-generated catch block			e.printStackTrace();		}		return fis;	}		public static InputStream fromStringToIputStream(String s) {	    if (s != null && !s.equals("")) {	        try {	            ByteArrayInputStream stringInputStream = new ByteArrayInputStream(	                    s.getBytes());	            return stringInputStream;	        } catch (Exception e) {	            e.printStackTrace();	        }	    }	    return null;	}	//把输入流转换为存有UTF-8格式数据的输入流	public static InputStream fromInputStreamToInputStreamInCharset(			InputStream in, String charset) throws Exception {		StringBuilder builder=new StringBuilder();		byte[] buffer = new byte[2048];		int len = -1;		while ((len = in.read(buffer)) != -1) {			builder.append(EncodingUtils.getString(buffer, 0, len, "UTF-8"));		}		return IOHelper.fromStringToIputStream(builder.toString());	}	}

本类中的主要实现效果是二级联动,所以API调用的DAO层代码我就不上传了。。

疑问:大家可能也注意到了,我的IOHelper类中,专门写了一个方法fromInputStreamToInputStreamInCharset来处理输入流,那是因为我发现我直接通过SAXReader.read(io)读取的时候,出现了乱码的现象,我知道是编码格式的问题,本来想直接让SAXReader以UTF-8格式来读取,可以搜了一圈,没找到合适的方法就专门写了一个这样的方法。希望更好处理方式的朋友麻烦告之下。

另外我现在实现的方式两个选项栏里面的数据都是无序的,大家有兴趣的可以写一个比较器来实现排序的效果。

最后附上最终实现的效果图:



  相关解决方案