接着昨天的任務,我們今天實現左右滑動可以切換城市的功能。
這里就需要引入新的控件了,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


