10天学安卓-第九天
接着昨天的任务,我们今天实现左右滑动可以切换城市的功能。
这里就需要引入新的控件了,Android给我们提供了ViewPager,我们就使用这个,同时,显示天气的界面我们也不再使用Activity,而改为Fragment。
Fragment
Fragment可以认为是可复用的UI组件,有自己的布局和完整的生命周期,可以处理本身的事件,但是必须依存于Activity,不能脱离Activity而存在。
可以看出来,Fragment的生命周期跟Activity非常相似,并且会随着Activity的销毁而销毁。
下面,我们来战。
首先,新建一个Fragment的子类,取名为WeatherFragment。
public class WeatherFragment extends Fragment { @Override public void onCreate( Bundle savedInstanceState ) { super.onCreate( savedInstanceState ); } @Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) { return super.onCreateView( inflater, container, savedInstanceState ); } }
这是用来显示天气的界面,而我们之前是直接在Activity中显示的,需要把这部分代码给移植到Fragment中。
这是个麻烦的过程,不过不要紧,慢慢来。
新建一个Layout,取名为frag_weather.xml,然后把activity_main.xml中的代码给复制过来,
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" > <ListView android:id="@+id/weather_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" > </ListView> </RelativeLayout>
我们让WeatherFragment使用新的Layout,再把MainActivity中关于天气的代码移植到WeatherFragment中,
public class WeatherFragment extends Fragment { @ViewInject( R.id.weather_list ) private ListView lstWeather; private WeatherAdapter adapter; private BaiduData data; private List<WeatherDataBean> datas; private String city; public void setCity( String city ) { this.city = city; } @Override public void onCreate( Bundle savedInstanceState ) { super.onCreate( savedInstanceState ); datas = new ArrayList<WeatherDataBean>(); adapter = new WeatherAdapter( getActivity(), datas ); } @Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) { View view = inflater.inflate( R.layout.frag_weather, null ); ViewUtils.inject( this, view ); lstWeather.setAdapter( adapter ); getWeather(); return view; } private void getWeather() { HttpUtils http = new HttpUtils(); RequestParams params = new RequestParams(); params.addQueryStringParameter( "location", city ); params.addQueryStringParameter( "output", "json" ); params.addQueryStringParameter( "ak", "YknGmxIoPugT7YrNrG955YLS" ); http.send( HttpMethod.GET, "http://api.map.baidu.com/telematics/v3/weather", params, new RequestCallBack<String>() { @Override public void onSuccess( ResponseInfo<String> responseInfo ) { String weather = responseInfo.result; Gson gson = new Gson(); data = gson.fromJson( weather, BaiduData.class ); datas.clear(); datas.addAll( data.getResults().get( 0 ).getWeather_data() ); adapter.notifyDataSetChanged(); Log.v( "onSuccess", data.toString() ); } @Override public void onFailure( HttpException arg0, String arg1 ) { Log.v( "onFailure", arg1 ); } } ); } }
然后,修改主页面activity_main.xml为:
<?xml version="1.0"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <LinearLayout android:id="@+id/viewGroup" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_marginBottom="30dp" android:gravity="center_horizontal" android:orientation="horizontal" > </LinearLayout> </RelativeLayout>
这里我们引入了ViewPager,并且还有一个LinearLayout,其中ViewPager我们用来显示天气,Linearlayout用来作为指示器,表示我们当前所选城市的次序。
之后,修改我们主页面的代码,主界面现在的作用主要是两个:
1. 初次启动的时候,获取所在地城市
2. 处理切换Fragment的逻辑
3. 处理页面跳转/返回的逻辑
public class MainActivity extends FragmentActivity { @ViewInject( R.id.viewPager ) private ViewPager pager; @ViewInject( R.id.viewGroup ) private LinearLayout layout; private MyAdapter mAdapter; private List<SelectCityBean> citys; private LocationClient mLocationClient; private BDLocationListener myListener; private List<ImageView> imageViews; @Override protected void onCreate( Bundle savedInstanceState ) { super.onCreate( savedInstanceState ); setContentView( R.layout.activity_main ); Log.v( "WeatherAPP", "onCreate" ); ViewUtils.inject( this ); imageViews = new ArrayList<ImageView>(); citys = readCity(); mAdapter = new MyAdapter( getSupportFragmentManager() ); pager.setAdapter( mAdapter ); pager.setOnPageChangeListener( new OnPageChangeListener() { @Override public void onPageSelected( int arg0 ) { setTitle( citys.get( arg0 ).getCityName() + "天气" ); setImageBackground( arg0 ); } @Override public void onPageScrolled( int arg0, float arg1, int arg2 ) { } @Override public void onPageScrollStateChanged( int arg0 ) { } } ); if( citys == null || citys.size() == 0 ) { citys = new ArrayList<SelectCityBean>(); initLocationClient(); mLocationClient.start(); } showIndicator( 0 ); } private void showIndicator( int position ) { layout.removeAllViews(); imageViews = new ArrayList<ImageView>(); pager.setCurrentItem( position ); for( int i = 0; i < citys.size(); i++ ) { ImageView imageView = new ImageView( this ); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( 20, 20 ); lp.leftMargin = 5; imageView.setLayoutParams( lp ); imageViews.add( imageView ); if( i == position ) { setTitle( citys.get( position ).getCityName() + "天气" ); imageView.setBackgroundResource( R.drawable.page_indicator_focused ); } else { imageView.setBackgroundResource( R.drawable.page_indicator_unfocused ); } layout.addView( imageView ); } } private void setImageBackground( int selectItems ) { for( int i = 0; i < imageViews.size(); i++ ) { if( i == selectItems ) { imageViews.get( i ).setBackgroundResource( R.drawable.page_indicator_focused ); } else { imageViews.get( i ).setBackgroundResource( R.drawable.page_indicator_unfocused ); } } } @Override public boolean onCreateOptionsMenu( Menu menu ) { super.onCreateOptionsMenu( menu ); menu.add( Menu.NONE, Menu.FIRST + 1, 0, "添加城市" ).setShowAsAction( MenuItem.SHOW_AS_ACTION_ALWAYS ); return true; } @Override public boolean onOptionsItemSelected( MenuItem item ) { if( item.getItemId() == Menu.FIRST + 1 ) { Intent intent = new Intent( getApplicationContext(), ChooseCityActivity.class ); intent.putExtra( "key", "value" ); startActivityForResult( intent, 99 ); } return super.onOptionsItemSelected( item ); } @Override protected void onActivityResult( int requestCode, int resultCode, Intent data ) { super.onActivityResult( requestCode, resultCode, data ); if( resultCode == RESULT_OK ) { String city = data.getStringExtra( "selectedCity" ); addCity( city ); } } private void initLocationClient() { mLocationClient = new LocationClient( getApplicationContext() ); // 声明LocationClient类 myListener = new MyLocationListener(); LocationClientOption option = new LocationClientOption(); option.setLocationMode( LocationMode.Hight_Accuracy ); option.setIsNeedAddress( true ); mLocationClient.setLocOption( option ); mLocationClient.registerLocationListener( myListener ); } @Override protected void onStop() { Log.v( "WeatherAPP", "onStop" ); super.onStop(); if( mLocationClient != null ) mLocationClient.stop(); } @Override protected void onPause() { Log.v( "WeatherAPP", "onPause" ); super.onPause(); } @Override protected void onRestart() { Log.v( "WeatherAPP", "onRestart" ); super.onRestart(); } @Override protected void onResume() { Log.v( "WeatherAPP", "onResume" ); super.onResume(); } @Override protected void onStart() { Log.v( "WeatherAPP", "onStart" ); super.onStart(); } @Override protected void onDestroy() { Log.v( "WeatherAPP", "onDestroy" ); super.onDestroy(); } public class MyLocationListener implements BDLocationListener { @Override public void onReceiveLocation( BDLocation location ) { String city = location.getCity(); addCity( city ); } } private void addCity( String city ) { SelectCityBean cityBean = new SelectCityBean(); cityBean.setCityName( city ); saveCity( cityBean ); if( citys == null ) citys = new ArrayList<SelectCityBean>(); citys.add( cityBean ); mAdapter.notifyDataSetChanged(); showIndicator( citys.size() - 1 ); } private void saveCity( SelectCityBean city ) { DbUtils dbUtils = WeatherApplication.getInstance().getDbUtil(); try { dbUtils.save( city ); } catch( DbException e ) { } } private List<SelectCityBean> readCity() { DbUtils dbUtils = WeatherApplication.getInstance().getDbUtil(); try { return dbUtils.findAll( SelectCityBean.class ); } catch( DbException e ) { return null; } } public class MyAdapter extends FragmentStatePagerAdapter { public MyAdapter( FragmentManager fm ) { super( fm ); } @Override public Fragment getItem( int arg0 ) { WeatherFragment fragment = new WeatherFragment(); fragment.setCity( citys.get( arg0 ).getCityName() ); return fragment; } @Override public int getItemPosition( Object object ) { return POSITION_NONE; } @Override public int getCount() { if( citys == null ) return 0; return citys.size(); } } }
基本上面目全非了,跟之前的代码完全不一样了,这里面的主要变动为:
1. saveCity、readCity不再从Preference中获取数据了,而改为从数据库获取
2. 增加了MyAdapter以及相关的ViewPager的逻辑
这里还用到了一个新的SelectCityBean以及两个图片资源,
public class SelectCityBean { private int id; private String cityName; public int getId() { return id; } public void setId( int id ) { this.id = id; } public String getCityName() { return cityName; } public void setCityName( String cityName ) { this.cityName = cityName; } }
两个图片资源分别代表了当前城市以及其他城市,
完成之后,运行来看看,我这边的效果是这样的:
你可以试着添加城市看看,是不是这样的效果。
今天的内容比较少,代码比较多,大家多多练习一下。
附件是本次的工程文件,点击下载 http://pan.baidu.com/s/1sj2V5fB 。
此系列文章系本人原创,如需转载,请注明出处 www.liuzhibang.cn