zoukankan      html  css  js  c++  java
  • 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格式来读取,可以搜了一圈,没找到合适的方法就专门写了一个这样的方法。希望更好处理方式的朋友麻烦告之下。

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

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



  • 相关阅读:
    c++模板类的使用,编译的问题
    js中对象深度拷贝的方法(浅拷贝)
    java8 Function 函数式接口的妙用
    Redis Web Ui管理工具
    前端省市联动,与django传递信息
    做人做事,行为规范
    几斤猫尿,醉享生活
    分布式系统之平台三大支柱
    祭奠十年,我今起步
    一步一步,从一而终
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3293630.html
Copyright © 2011-2022 走看看