制作未来6天天气界面

小组成员: 盛意林、刘艺霞、李仕聪、胡玉、宫翠峰   最终完成日期:15年11月30日

一、简介

本模块是制作天气预报项目中的未来6天天气界面。

二、基础知识

  • 知识点1:ViewPager控件

    ViewPager控件可以用来制作程序的引导页面,也可以在界面中制作多个视图切换的效果。其使用流程为:
      1. 在布局文件中增加ViewPager控件:Android提供了兼容低版本终端的的android.support.v4.view.ViewPager
      2. 自定义一个PagerAdapter
      3. 初始化要展示的页面列表
      4. 在Activity里实例化ViewPager控件,并设置它的Adapter
    
  • 知识点2:PagerAdapter适配器

    实现一个PagerAdapter, 至少需要重写以下几个方法:
      1、instantiateItem(ViewGroup, int)
          //将当前视图添加到container中,返回当前View
      2、destroyItem(ViewGroup, int, Object)
          //从当前container中删除指定位置(position)的View
      3、getCount()
          //返回要滑动的View的个数
      4、isViewFromObject(View, Object)
          //该函数用于判断instantiateItem(ViewGroup, int)返回的对象是否与当前View代表的是同一个对象
    
  • 知识点3:

    知识点介绍
    

三、主要思路及步骤

3.1 主要思路

本模块我们主要完成了两个工作:
1、在主布局中添加了ViewPager控件,并创建两个布局文件,用于对未来六天的天气信息进行布局,并把它们加载到ViewPager中的视图;
2、把XML中对未来天气解析出来的数据动态显示到布局文件中

3.2 实践步骤

我们主要分为三个步骤来进行:

第一步:在主布局中通过ViewPager来添加一周天气信息的布局

1、在主布局中添加一周天气信息布局以及ViewPager控件

    <!--七日天气信息-->
    <RelativeLayout
        android:id="@+id/future_info"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="10.0dip">

        <android.support.v4.view.ViewPager
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:id="@+id/viewpager">

        </android.support.v4.view.ViewPager>

    </RelativeLayout>

2、创建两个布局文件page1.xml和page2.xml,用于加载到ViewPager中的视图

    在page1.xml添加3个线性布局:

    其中每个LinearLayout中添加的控件如下:
    <LinearLayout
        android:id="@+id/one_info"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="vertical">
        <TextView
            android:id="@+id/weekDay1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:singleLine="true"
            android:text="星期五"
            android:textColor="@android:color/white"
            android:textSize="15sp"/>
        <ImageView
            android:id="@+id/imageDay1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:src="@mipmap/biz_plugin_qing"/>
        <TextView
            android:id="@+id/temperatureDay1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:singleLine="true"
            android:text="-2℃~-7℃"
            android:textColor="@android:color/white"
            android:textSize="15sp"/>
        <TextView
            android:id="@+id/climateDay1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:singleLine="true"
            android:text="多云转晴"
            android:textColor="@android:color/white"
            android:textSize="15sp"/>
        <TextView
            android:id="@+id/windDay1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:singleLine="true"
            android:text="微风"
            android:textColor="@android:color/white"
            android:textSize="15sp"/>
    </LinearLayout>
    其余的LinearLayout以及page2.xml都与上面类似,不再赘述。

3、创建一个ViewPagerAdapter类,继承自基类PagerAdapter

    public class ViewPagerAdapter extends PagerAdapter {
        private List<View> views;
        private Context context;

        public ViewPagerAdapter(List<View> views, Context context) {
            this.views = views;
            this.context = context;
        }

        @Override
        public int getCount() {
            return views.size();
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            container.addView(views.get(position));
            return views.get(position);
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView(views.get(position));
        }

        @Override
        public boolean isViewFromObject(View view, Object o) {
            return (view == o);
        }
    }

4、在MainActivity.java中声明ViewPagerAdapter对象、ViewPager对象、List<>集合

        private ViewPagerAdapter vpAdapter;
        private ViewPager vp;
        private List<View> views;

5、在initView()函数中添加如下语句,用于动态加载page1.xml和page2.xml

        LayoutInflater inflater = LayoutInflater.from(this);
        View one_page = inflater.inflate(R.layout.page1, null);
        View two_page = inflater.inflate(R.layout.page2, null);
        views = new ArrayList<View>();
        views.add(one_page);
        views.add(two_page);
        vpAdapter = new ViewPagerAdapter(views, this);
        vp = (ViewPager)findViewById(R.id.viewpager);
        vp.setAdapter(vpAdapter);

6、运行结果如下所示:

第二步:添加导航小圆点

1、在一周天气信息布局中添加ImageView控件(将图片资源复制到drawable目录下)

        <LinearLayout
            android:id="@+id/indicator"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_alignParentBottom="true"
            android:gravity="center_horizontal">
            <ImageView
                android:id="@+id/iv1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="5dp"
                android:src="@drawable/page_indicator_focused"/>

            <ImageView
                android:id="@+id/iv2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="5dp"
                android:src="@drawable/page_indicator_unfocused"/>
        </LinearLayout>

2、在MainActivity.java中,增加页面变化的监听事件,动态修改导航小圆点的属性

    添加如下属性:
        private ImageView[] dots;
        private int[] ids = {R.id.iv1, R.id.iv2};
    添加如下方法:
        private void initDots() {
            dots = new ImageView[views.size()];
            for (int i=0; i<views.size(); i++) {
                dots[i] = (ImageView)findViewById(ids[i]);
            }
        }

3、在onCreate()方法中调用initDots()方法

4、实现OnPageChangeListener接口,并重写相应的方法

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {
            for (int a=0; a<ids.length; a++) {
                if (a==position) {
                    dots[a].setImageResource(R.drawable.page_indicator_focused);
                } else {
                    dots[a].setImageResource(R.drawable.page_indicator_unfocused);
                }
            }
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    在initView()中添加如下语句:

5、运行程序,如下所示:

第三步:根据XML数据更新ViewPager中的天气信息

注意:由于本块的代码对未来六天的处理方式较为类似,所以我们只给出部分关键代码。

1、在TodayWeather.java中实现Serializable接口(即public class TodayWeather implements Serializable ),并添加如下属性,用于保存昨天的信息,添加其set和get方法

        private String fdate0;
        private String fhigh0;
        private String flow0;
        private String ftype0;
        private String ffengxiang0;

2、新建FutureWeather.java文件,用于保存未来天气,添加如下属性,并添加其set和get方法

        private String fdate;
        private String fhigh;
        private String flow;
        private String ftype;
        private String ffengxiang;

3、在MainActivity.java中private TodayWeather parseXML(String xmldata)方法中添加如下语句,保存从XML文件中解析出来的昨天天气信息:

        case XmlPullParser.START_TAG:
            if(xmlPullParser.getName().equals("resp")) {
                todayWeather = new TodayWeather();
            }
            if (todayWeather != null) {
                if (xmlPullParser.getName().equals("city")) {
                    ……
                } else if (xmlPullParser.getName().equals("date_1")) {
                    eventType = xmlPullParser.next();
                    todayWeather.setFdate0(xmlPullParser.getText());
                }  else if (xmlPullParser.getName().equals("high_1")) {
                    eventType = xmlPullParser.next();
                    todayWeather.setFhigh0(xmlPullParser.getText().substring(2).trim());
                } else if (xmlPullParser.getName().equals("low_1")) {
                    eventType = xmlPullParser.next();
                    todayWeather.setFlow0(xmlPullParser.getText().substring(2).trim());
                }else if (xmlPullParser.getName().equals("type_1") && type_1Count==0) {
                    eventType = xmlPullParser.next();
                    todayWeather.setFtype0(xmlPullParser.getText());
                    type_1Count++;
                } else if (xmlPullParser.getName().equals("fx_1") && fx_1Count==0) {
                    eventType = xmlPullParser.next();
                    todayWeather.setFfengxiang0(xmlPullParser.getText());
                    fx_1Count++;
                }
            }
            break;

4、在MainActivity.java中添加private List pullParseXML(String xmldata)方法来解析未来天气:

    private List<FutureWeather> pullParseXML(String xmldata) {
        List<FutureWeather> lists = null;
        FutureWeather futureWeather = null;
        try{
            int typeCou = 0;
            int fengxiangCou = 0;
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            XmlPullParser pullParser = factory.newPullParser();
            pullParser.setInput(new StringReader(xmldata));
            int eventType = pullParser.getEventType();
            while(eventType != XmlPullParser.END_DOCUMENT) {
                switch (eventType) {
                    case XmlPullParser.START_DOCUMENT:
                        lists = new ArrayList<FutureWeather>();
                        break;
                    case XmlPullParser.START_TAG:
                        if(pullParser.getName().equals("weather")) {
                            futureWeather = new FutureWeather();
                        }
                        if (futureWeather != null) {
                            if (pullParser.getName().equals("date")) {
                                eventType = pullParser.next();
                                futureWeather.setFdate(pullParser.getText());
                            } else if (pullParser.getName().equals("high")) {
                                eventType = pullParser.next();
                                futureWeather.setFhigh(pullParser.getText().substring(2).trim());
                            } else if (pullParser.getName().equals("low")) {
                                eventType = pullParser.next();
                                futureWeather.setFlow(pullParser.getText().substring(2).trim());
                            } else if (pullParser.getName().equals("type") && typeCou==0) {
                                eventType = pullParser.next();
                                futureWeather.setFtype(pullParser.getText());
                                typeCou++;
                            } else if (pullParser.getName().equals("fengxiang") && fengxiangCou==0) {
                                eventType = pullParser.next();
                                futureWeather.setFfengxiang(pullParser.getText());
                                fengxiangCou++;
                            }
                        }
                        break;
                    case XmlPullParser.END_TAG:
                        if (pullParser.getName().equals("weather")) {
                            lists.add(futureWeather);
                            futureWeather = null;
                            typeCou = 0;
                            fengxiangCou = 0;
                        }
                        break;
                    default:
                        break;
                }
                eventType = pullParser.next();
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        return lists;
    }

5、在MainActivity.java的queryWeatherCode()函数中修改消息发送代码,如下:

        TodayWeather todayWeather1 = parseXML(responseStr);
        List<FutureWeather> lists = pullParseXML(responseStr);
        if(todayWeather1 != null && lists != null) {
            Message msg = new Message();
            msg.what = UPDATE_TODAY_WEATHER;
            msg.obj = lists;
            Bundle data = new Bundle();
            data.putSerializable("todayWeather", todayWeather1);
            msg.setData(data);
            mHandler.sendMessage(msg);
        }

6、修改Handler代码,如下:

        private Handler mHandler = new Handler() {
            public void handleMessage(android.os.Message msg) {
                switch (msg.what) {
                    case UPDATE_TODAY_WEATHER:
                        TodayWeather todayWeather = (TodayWeather)msg.getData().get("todayWeather");
                        List<FutureWeather> list = (List<FutureWeather>)msg.obj;
                        updateTodayWeather(todayWeather, list);
                        break;
                    default:
                        break;
                }
            }
        };

7、在MainActivity.java中添加changeFurureWeatherImg()方法,用于动态修改天气图片

        void changeFurureWeatherImg(ImageView view, String str) {
            if(str.equals("暴雪")) {
                view.setImageResource(R.mipmap.biz_plugin_baoxue);
            } else if (str.equals("暴雨")) {
                view.setImageResource(R.mipmap.biz_plugin_baoyu);
            } else if (str.equals("大暴雨")) {
                view.setImageResource(R.mipmap.biz_plugin_dabaoyu);
            } else if (str.equals("大雪")) {
                view.setImageResource(R.mipmap.biz_plugin_daxue);
            } else if (str.equals("大雨")) {
                view.setImageResource(R.mipmap.biz_plugin_dayu);
            } else if (str.equals("多云")) {
                view.setImageResource(R.mipmap.biz_plugin_duoyun);
            } else if (str.equals("雷阵雨")) {
                view.setImageResource(R.mipmap.biz_plugin_leizhenyu);
            } else if (str.equals("雷阵雨冰雹")) {
                view.setImageResource(R.mipmap.biz_plugin_leizhenyubingbao);
            } else if (str.equals("晴")) {
                view.setImageResource(R.mipmap.biz_plugin_qing);
            } else if (str.equals("沙尘暴")) {
                view.setImageResource(R.mipmap.biz_plugin_shachenbao);
            } else if (str.equals("特大暴雨")) {
                view.setImageResource(R.mipmap.biz_plugin_tedabaoyu);
            } else if (str.equals("雾")) {
                view.setImageResource(R.mipmap.biz_plugin_wu);
            } else if (str.equals("小雪")) {
                view.setImageResource(R.mipmap.biz_plugin_xiaoxue);
            } else if (str.equals("小雨")) {
                view.setImageResource(R.mipmap.biz_plugin_xiaoyu);
            } else if (str.equals("阴")) {
                view.setImageResource(R.mipmap.biz_plugin_yin);
            } else if (str.equals("雨夹雪")) {
                view.setImageResource(R.mipmap.biz_plugin_yujiaxue);
            } else if (str.equals("阵雪")) {
                view.setImageResource(R.mipmap.biz_plugin_zhenxue);
            } else if (str.equals("阵雨")) {
                view.setImageResource(R.mipmap.biz_plugin_zhenyu);
            } else if (str.equals("中雪")) {
                view.setImageResource(R.mipmap.biz_plugin_zhongxue);
            } else if (str.equals("中雨")) {
                view.setImageResource(R.mipmap.biz_plugin_zhongyu);
            }
        }

8、在initview()中添加如下语句,对page1.xml和page2.xml中的控件进行监控

    private TextView[] FurWeeks = new TextView[6];
    private TextView[] FurTemps = new TextView[6];
    private TextView[] FurClis = new TextView[6];
    private TextView[] FurWinds = new TextView[6];
    private ImageView[] FurImages = new ImageView[6];

    ————只列部分绑定控件代码,其余类似
        FurWeeks[0] = (TextView)one_page.findViewById(R.id.weekDay1);
        FurTemps[0] = (TextView)one_page.findViewById(R.id.temperatureDay1);
        FurClis[0] = (TextView)one_page.findViewById(R.id.climateDay1);
        FurWinds[0] = (TextView)one_page.findViewById(R.id.windDay1);
        FurImages[0] = (ImageView)one_page.findViewById(R.id.imageDay1);

9、在updateTodayWeather()方法中添加如下语句,用于在界面更新未来天气:

    void updateTodayWeather(TodayWeather todayWeather, List<FutureWeather> lists) {
        ……

        //昨天天气
        FurWeeks[0].setText(todayWeather.getFdate0());
        FurTemps[0].setText(todayWeather.getFhigh0() + "~" + todayWeather.getFlow0());
        FurClis[0].setText(todayWeather.getFtype0());
        FurWinds[0].setText(todayWeather.getFfengxiang0());
        if (todayWeather.getFtype0()!=null) {
            changeFurureWeatherImg(FurImages[0], todayWeather.getFtype0());
        }

        //未来5天
        for (int i=0; i<lists.size(); i++) {
            FutureWeather futureWeather = lists.get(i);
            FurWeeks[i+1].setText(futureWeather.getFdate());
            FurTemps[i+1].setText(futureWeather.getFhigh() + "~" + futureWeather.getFlow());
            FurClis[i+1].setText(futureWeather.getFtype());
            FurWinds[i+1].setText(futureWeather.getFfengxiang());
            if (futureWeather.getFtype() != null) {
                changeFurureWeatherImg(FurImages[i+1], futureWeather.getFtype());
            }
        }

        ……
    }

10、运行结果如下:

四、常见问题及注意事项

1、添加ViewPager控件的时候,是使用android.support.v4.view.ViewPager。viewpager不识别。
    主要是因为需要用到android-support-v4 jar里面的类和函数,但又没有自动加载,导致报错
    解决办法一:添加依赖项,Click on File--> Project Structure--->Dependencies----> "+"----->choose Library DependenciesSelect support-v4 
    解决方法二:在安装目录下 AppData\Local\Android\sdk\extras\android\support\v4 拷贝 android-support-v4.jar,然后复制到项目目录下app\libs下面就可以啦。

2、如何在主Activity中获取ViewPager中增加的布局页面的控件,并修改其值?
    由于在ViewPager中加载的布局文件是未来六天的天气信息,所以需要在MainActivity.java中对其控件进行监听,但是直接通过findViewById()方法是不能绑定该控件的,因为在MainActivity.java中只通过setContentView(R.layout.weather_info)绑定了主布局,所以其他.xml中的控件是不能直接操作的。
    解决办法:
    LayoutInflater inflater = LayoutInflater.from(this);
    View one_page = inflater.inflate(R.layout.page1, null);
    View two_page = inflater.inflate(R.layout.page2, null);

    weekD1 = (TextView)one_page.findViewById(R.id.weekDay1);

    //inflater.inflate(R.layout.xxx, null) 返回的是当前指定的xml的生成的View对象,可以把inflater理解为xml视图解析器。通过这种方式就可以监听了

3、在做对不同天气类型更新相应的图片时,一定要做信息为空的时候做处理

4、注意XML的解析

results matching ""

    No results matching ""