接着昨天的任务,我们今天实现左右滑动可以切换城市的功能。
这里就需要引入新的控件了,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

