個(gè)人博客CoorChice躲撰,https://chenbingx.github.io/ 针贬,最新文章將會(huì)首發(fā)CoorChice的博客,歡迎探索哦 !
同時(shí)拢蛋,搜索CoorChice
關(guān)注我的微信公眾號(hào)桦他,同期文章也將會(huì)優(yōu)先推送到公眾號(hào)中,以提醒您有新鮮文章出爐谆棱。亦可在文章末尾掃描二維碼關(guān)注快压。
本系列文章列表
截止上一篇圆仔,我們已經(jīng)完成了歡迎頁(yè),并且成功的請(qǐng)求到了定位地點(diǎn)的天氣數(shù)據(jù)蔫劣,并且緩存起來(lái)坪郭。本篇我們將開(kāi)始構(gòu)建我們的核心主頁(yè),它用于展示天氣數(shù)據(jù)脉幢。
主頁(yè)需求
- 能夠展示未來(lái)幾天的天氣截粗;
- 能夠展示當(dāng)日的詳細(xì)天氣情況;
- 能夠展示多地天氣鸵隧。
暫時(shí)先這幾條绸罗,我們后面還可以再添加。現(xiàn)在我們開(kāi)始著手實(shí)現(xiàn)這幾個(gè)需求豆瘫。
實(shí)現(xiàn)需求
根據(jù)以上需求珊蟀,我們不但需要展示一天的詳細(xì)數(shù)據(jù)和未來(lái)幾天的天氣數(shù)據(jù),還要具備展示多地天氣數(shù)據(jù)外驱。所以大概可以設(shè)計(jì)一下育灸,使用列表控件 來(lái)展示一個(gè)地區(qū)的詳細(xì)數(shù)據(jù),使用ViewPager 來(lái)展示不同地區(qū)的詳細(xì)數(shù)據(jù)昵宇。話不多說(shuō)磅崭,來(lái)看看這樣的效果圖。
主要xml文件
這個(gè)頁(yè)面很簡(jiǎn)單瓦哎,它由Activity和Fragment構(gòu)成砸喻。Fragments被放到了ViewPager中。
下面來(lái)看看各個(gè)布局文件蒋譬。
Activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/themeBlueDeep"
android:clipChildren="false"
android:gravity="center"
tools:background="@color/themeBlueDeep"
tools:context="com.chenbing.oneweather.View.activitys.MainActivity"
>
//用來(lái)容納Fragment
<android.support.v4.view.ViewPager
android:id="@+id/pager_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bottom_opration"
android:layout_alignParentStart="true"
android:background="@color/transparent"
tools:background="@color/opacity_7_white"
/>
//后期會(huì)在底部添加操作欄割岛,所以先留出位置。
<RelativeLayout
android:id="@+id/bottom_opration"
android:layout_width="match_parent"
android:layout_height="46dp"
android:background="@color/transparent"
tools:background="@color/opacity_5_red"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true">
<include layout="@layout/line_white"/>
<ImageView
android:id="@+id/right_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="8dp"
tools:src="@drawable/sun"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toLeftOf="@+id/left_button"
android:layout_toRightOf="@+id/right_button"
>
</LinearLayout>
<ImageView
android:id="@+id/left_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:padding="8dp"
tools:src="@drawable/sun"
/>
</RelativeLayout>
</RelativeLayout>
Fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
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"
tools:background="@color/colorPrimary"
>
<LinearLayout android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="@+id/city_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:gravity="center"
android:textColor="@color/white"
android:textSize="35sp"
tools:text="北京市"
/>
<TextView
android:id="@+id/weather_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:gravity="center"
android:textColor="@color/white"
android:textSize="14sp"
tools:text="多云"
/>
<TextView
android:id="@+id/air_quality"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="center"
android:textColor="@color/white"
android:textSize="14sp"
tools:text="空氣質(zhì)量:危害健康"
/>
<TextView
android:id="@+id/temperature"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:gravity="center_horizontal"
android:textColor="@color/white"
android:textSize="80sp"
tools:text="3°"/>
</LinearLayout>
//用來(lái)裝未來(lái)天氣數(shù)據(jù)和當(dāng)日詳細(xì)信息
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingTop="270dp"
tools:listitem="@layout/item_future_weather_info"
/>
</FrameLayout>
Activity
這個(gè)Activity的結(jié)構(gòu)和之前的歡迎頁(yè)差不多犯助。
View模塊
首先創(chuàng)建MainActivity的接口癣漆。
public interface MainActivityView extends MvpView {
}
繼承接口,創(chuàng)建Activity剂买。
public class MainActivity extends BaseActivity implements MainActivityView {
@BindView(R.id.pager_container)
ViewPager pagerContainer;
private MainActivityPresenterApi presenter; //依賴(lài)Presenter的抽象
private List<BaseFragment> fragments = new ArrayList<>(); //這個(gè)數(shù)組用來(lái)裝每個(gè)地區(qū)的天氣頁(yè)面
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
presenter = new MainActivityPresenter(this);
ButterKnife.bind(this);
initData();
initView();
addListener();
}
@Override
protected void initData() {
fragments.add(WeatherDetailFragment.newInstance(null)); //創(chuàng)建Fragment
//這里之所以穿Null是因?yàn)槲以诤竺嫣幚頃r(shí)惠爽,把默認(rèn)天氣數(shù)據(jù)設(shè)置為定位地區(qū)的
}
@Override
protected void initView() {
setWindowProperties();
//設(shè)置ViewPager的適配器
pagerContainer.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
});
pagerContainer.setPageTransformer(false, new ZoomOutPageTransformer());
}
private void setWindowProperties() {
// 實(shí)現(xiàn)透明狀態(tài)欄
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
getWindow().setFormat(PixelFormat.TRANSPARENT);
}
@Override
protected void addListener() {
}
@Override
protected BasePresenter getPresenter() {
return presenter;
}
}
Presenter模塊
由于目前Activity本身并不處理什么任務(wù),所以Presenter中還沒(méi)內(nèi)容瞬哼,但是我們?nèi)稳灰凑占軜?gòu)寫(xiě)婚肆,因?yàn)楹竺婵赡軙?huì)添加?xùn)|西進(jìn)去。
//Presenter接口
public interface MainActivityPresenterApi extends BasePresenter {
}
//Presenter實(shí)現(xiàn)倒槐,因?yàn)闀簳r(shí)不處理事物旬痹,所以先不寫(xiě)Model了
public class MainActivityPresenter implements MainActivityPresenterApi {
private MainActivityView view;
public MainActivityPresenter(MainActivityView view) {
this.view = view;
}
@Override
public void destroy() {
view = null;
}
}
Fragment
上面代碼中可以看到,我們已經(jīng)創(chuàng)建了一個(gè)Fragment讨越,下面就來(lái)看看這個(gè)Fragment是什么樣的两残。
Fragment同樣需要按照MVP模式來(lái),首先需要改造一下BaseFragment把跨。
public abstract class BaseFragment extends Fragment {
abstract protected void initData();
abstract protected void initView();
abstract protected void addListener();
/**
* 創(chuàng)建Presenter后必須重寫(xiě)這個(gè)方法人弓,將其作為返回值
*/
abstract protected BasePresenter getPresenter();
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.setClickable(true); //這個(gè)操作是為了防止Fragment出現(xiàn)點(diǎn)透Bug
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (getPresenter() != null){
getPresenter().destroy(); //銷(xiāo)毀Presenter,避免Activity對(duì)象因被Presenter持有而不能被銷(xiāo)毀
}
}
}
View模塊
Fragment的接口着逐。
public interface WeatherDetailFragmentView extends MvpView {
void onWeatherDataUpdate(WeatherData data); //通知View更新數(shù)據(jù)崔赌,這個(gè)方法供Presenter調(diào)用
}
實(shí)現(xiàn)Fragment,包含了交互操作耸别。
public class WeatherDetailFragment extends BaseFragment implements WeatherDetailFragmentView {
public static final String CITY_NAME = "city_name";
@BindView(R.id.header)
ViewGroup header;
@BindView(R.id.city_name)
TextView cityName;
@BindView(R.id.weather_info)
TextView weatherInfo;
@BindView(R.id.air_quality)
TextView airQuality;
@BindView(R.id.temperature)
TextView temperature;
@BindView(R.id.recyclerView)
RecyclerView recyclerView;
private WeatherDetailFragmentPresenterApi presenter; //依賴(lài)Presenter的抽象
private WeatherData data;
private FutureWeathersAdapter adapter;
private int totalDy;
private int alphaReferenceValue;
public static BaseFragment newInstance(String cityName) { //用靜態(tài)方法創(chuàng)建Fragment
WeatherDetailFragment instance = new WeatherDetailFragment();
Bundle args = new Bundle();
args.putString(CITY_NAME, cityName); //儲(chǔ)存需要顯示的地區(qū)名字在Fragment的Argument中
instance.setArguments(args);
return instance;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_weather_detail, container, false);
ButterKnife.bind(this, rootView);
presenter = new WeatherDetailFragmentPresenter(this); //創(chuàng)建Fragment的Presenter
initData();
initView();
addListener();
return rootView;
}
@Override
protected void initData() {
String cityName = getArguments().getString(CITY_NAME);
presenter.getWeatherData(cityName); //請(qǐng)求天氣數(shù)據(jù)
}
@Override
protected void initView() {
//看上面效果圖健芭,我們只需要使用LinearLayoutManager就可以了
recyclerView.setLayoutManager(
new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
recyclerView.setItemAnimator(new DefaultItemAnimator());
}
@Override
protected void addListener() {
listenRecyclerView();
temperature.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
computeAlphaReferenceValue();
temperature.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
private void computeAlphaReferenceValue() {
//下面是在計(jì)算設(shè)置溫度TextView的Alpha值的參考值,效果是在RecyclerView的第一個(gè)Item滑動(dòng)到溫度TextView的1/8時(shí)秀姐,溫度TextView剛好完全透明
int temperatureY = temperature.getBottom();
int temperatureHeight = temperature.getMeasuredHeight();
int recyclerViewPaddingTop = recyclerView.getPaddingTop();
alphaReferenceValue = recyclerViewPaddingTop - temperatureY + temperatureHeight / 8;
}
private void listenRecyclerView() {
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
totalDy -= dy; //記錄RecyclerView滑動(dòng)的距離慈迈,上滑為負(fù),下滑為正
float translationY = (float) (totalDy * 0.3); //取滑動(dòng)距離的30%來(lái)移動(dòng)上半部分View才能造成層次感
header.setTranslationY(translationY); //設(shè)置整個(gè)上半部分View的TranslationY省有,實(shí)現(xiàn)圖中的滑動(dòng)效果痒留。
//translationY初始值為0,負(fù)值向上移動(dòng)蠢沿,正值向下移動(dòng)伸头,與Android坐標(biāo)系的方向是一致的
float alpha = 1 - (float) (Math.abs(totalDy * 0.3)) / alphaReferenceValue;
temperature.setAlpha(alpha); //設(shè)置Alpha值
super.onScrolled(recyclerView, dx, dy);
}
});
}
@Override
protected BasePresenter getPresenter() {
return presenter;
}
@Override
public void onWeatherDataUpdate(WeatherData data) {
if (data != null) {
updateView(data.getData());
}
}
private void updateView(WeatherData.Data data) {
setHeaderView(data);
setRecyclerView(data);
}
private void setHeaderView(WeatherData.Data data) {
String cityName = data.getRealtime().getCity_name();
this.cityName.setText(cityName);
String weatherInfo = data.getRealtime().getWeather().getInfo();
this.weatherInfo.setText(weatherInfo);
String airQualityStrFormat = getString(R.string.air_quality);
String airQuality = String.format(airQualityStrFormat, data.getPm25().getPm25().getQuality());
this.airQuality.setText(airQuality);
String temperatureFormat = getString(R.string.temperature);
String temperature =
String.format(temperatureFormat, data.getRealtime().getWeather().getTemperature());
this.temperature.setText(temperature);
}
private void setRecyclerView(WeatherData.Data data) {
if (data == null) {
return;
}
if (adapter == null) {
recyclerView.setAdapter(new FutureWeathersAdapter(getActivity(), data)); //在這里才創(chuàng)建RecyclerView的Adapter
} else {
adapter.updateData(data);
}
}
}
由于篇幅問(wèn)題,本篇先講到這舷蟀。后面的文章中我們?cè)谝黄鹜瓿蒄ragment的Presenter恤磷、Model,以及編寫(xiě)RecyclerView的Adapter野宜。
本項(xiàng)目已上傳至GitHub碗殷,詳細(xì)源碼請(qǐng)到GitHub查看。
項(xiàng)目地址GitHub
截止上一篇速缨,我們已經(jīng)完成了歡迎頁(yè)锌妻,并且成功的請(qǐng)求到了定位地點(diǎn)的天氣數(shù)據(jù),并且緩存起來(lái)。本篇我們將開(kāi)始構(gòu)建我們的核心主頁(yè)颈渊,它用于展示天氣數(shù)據(jù)班缎。
主頁(yè)需求
- 能夠展示未來(lái)幾天的天氣;
- 能夠展示當(dāng)日的詳細(xì)天氣情況吭历;
- 能夠展示多地天氣。
暫時(shí)先這幾條擂橘,我們后面還可以再添加∩吻現(xiàn)在我們開(kāi)始著手實(shí)現(xiàn)這幾個(gè)需求。
實(shí)現(xiàn)需求
根據(jù)以上需求,我們不但需要展示一天的詳細(xì)數(shù)據(jù)和未來(lái)幾天的天氣數(shù)據(jù)朗若,還要具備展示多地天氣數(shù)據(jù)恼五。所以大概可以設(shè)計(jì)一下,使用列表控件 來(lái)展示一個(gè)地區(qū)的詳細(xì)數(shù)據(jù)哭懈,使用ViewPager 來(lái)展示不同地區(qū)的詳細(xì)數(shù)據(jù)灾馒。話不多說(shuō),來(lái)看看這樣的效果圖遣总。
主要xml文件
這個(gè)頁(yè)面很簡(jiǎn)單睬罗,它由Activity和Fragment構(gòu)成。Fragments被放到了ViewPager中旭斥。
下面來(lái)看看各個(gè)布局文件容达。
Activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/themeBlueDeep"
android:clipChildren="false"
android:gravity="center"
tools:background="@color/themeBlueDeep"
tools:context="com.chenbing.oneweather.View.activitys.MainActivity"
>
//用來(lái)容納Fragment
<android.support.v4.view.ViewPager
android:id="@+id/pager_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bottom_opration"
android:layout_alignParentStart="true"
android:background="@color/transparent"
tools:background="@color/opacity_7_white"
/>
//后期會(huì)在底部添加操作欄,所以先留出位置垂券。
<RelativeLayout
android:id="@+id/bottom_opration"
android:layout_width="match_parent"
android:layout_height="46dp"
android:background="@color/transparent"
tools:background="@color/opacity_5_red"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true">
<include layout="@layout/line_white"/>
<ImageView
android:id="@+id/right_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="8dp"
tools:src="@drawable/sun"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toLeftOf="@+id/left_button"
android:layout_toRightOf="@+id/right_button"
>
</LinearLayout>
<ImageView
android:id="@+id/left_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:padding="8dp"
tools:src="@drawable/sun"
/>
</RelativeLayout>
</RelativeLayout>
Fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
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"
tools:background="@color/colorPrimary"
>
<LinearLayout android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="@+id/city_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:gravity="center"
android:textColor="@color/white"
android:textSize="35sp"
tools:text="北京市"
/>
<TextView
android:id="@+id/weather_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:gravity="center"
android:textColor="@color/white"
android:textSize="14sp"
tools:text="多云"
/>
<TextView
android:id="@+id/air_quality"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="center"
android:textColor="@color/white"
android:textSize="14sp"
tools:text="空氣質(zhì)量:危害健康"
/>
<TextView
android:id="@+id/temperature"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:gravity="center_horizontal"
android:textColor="@color/white"
android:textSize="80sp"
tools:text="3°"/>
</LinearLayout>
//用來(lái)裝未來(lái)天氣數(shù)據(jù)和當(dāng)日詳細(xì)信息
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingTop="270dp"
tools:listitem="@layout/item_future_weather_info"
/>
</FrameLayout>
Activity
這個(gè)Activity的結(jié)構(gòu)和之前的歡迎頁(yè)差不多花盐。
View模塊
首先創(chuàng)建MainActivity的接口。
public interface MainActivityView extends MvpView {
}
繼承接口圆米,創(chuàng)建Activity卒暂。
public class MainActivity extends BaseActivity implements MainActivityView {
@BindView(R.id.pager_container)
ViewPager pagerContainer;
private MainActivityPresenterApi presenter; //依賴(lài)Presenter的抽象
private List<BaseFragment> fragments = new ArrayList<>(); //這個(gè)數(shù)組用來(lái)裝每個(gè)地區(qū)的天氣頁(yè)面
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
presenter = new MainActivityPresenter(this);
ButterKnife.bind(this);
initData();
initView();
addListener();
}
@Override
protected void initData() {
fragments.add(WeatherDetailFragment.newInstance(null)); //創(chuàng)建Fragment
//這里之所以穿Null是因?yàn)槲以诤竺嫣幚頃r(shí),把默認(rèn)天氣數(shù)據(jù)設(shè)置為定位地區(qū)的
}
@Override
protected void initView() {
setWindowProperties();
//設(shè)置ViewPager的適配器
pagerContainer.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
});
pagerContainer.setPageTransformer(false, new ZoomOutPageTransformer());
}
private void setWindowProperties() {
// 實(shí)現(xiàn)透明狀態(tài)欄
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
getWindow().setFormat(PixelFormat.TRANSPARENT);
}
@Override
protected void addListener() {
}
@Override
protected BasePresenter getPresenter() {
return presenter;
}
}
Presenter模塊
由于目前Activity本身并不處理什么任務(wù)娄帖,所以Presenter中還沒(méi)內(nèi)容也祠,但是我們?nèi)稳灰凑占軜?gòu)寫(xiě),因?yàn)楹竺婵赡軙?huì)添加?xùn)|西進(jìn)去近速。
//Presenter接口
public interface MainActivityPresenterApi extends BasePresenter {
}
//Presenter實(shí)現(xiàn)诈嘿,因?yàn)闀簳r(shí)不處理事物,所以先不寫(xiě)Model了
public class MainActivityPresenter implements MainActivityPresenterApi {
private MainActivityView view;
public MainActivityPresenter(MainActivityView view) {
this.view = view;
}
@Override
public void destroy() {
view = null;
}
}
Fragment
上面代碼中可以看到削葱,我們已經(jīng)創(chuàng)建了一個(gè)Fragment奖亚,下面就來(lái)看看這個(gè)Fragment是什么樣的。
Fragment同樣需要按照MVP模式來(lái)析砸,首先需要改造一下BaseFragment昔字。
public abstract class BaseFragment extends Fragment {
abstract protected void initData();
abstract protected void initView();
abstract protected void addListener();
/**
* 創(chuàng)建Presenter后必須重寫(xiě)這個(gè)方法,將其作為返回值
*/
abstract protected BasePresenter getPresenter();
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.setClickable(true); //這個(gè)操作是為了防止Fragment出現(xiàn)點(diǎn)透Bug
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (getPresenter() != null){
getPresenter().destroy(); //銷(xiāo)毀Presenter首繁,避免Activity對(duì)象因被Presenter持有而不能被銷(xiāo)毀
}
}
}
View模塊
Fragment的接口作郭。
public interface WeatherDetailFragmentView extends MvpView {
void onWeatherDataUpdate(WeatherData data); //通知View更新數(shù)據(jù),這個(gè)方法供Presenter調(diào)用
}
實(shí)現(xiàn)Fragment弦疮,包含了交互操作夹攒。
public class WeatherDetailFragment extends BaseFragment implements WeatherDetailFragmentView {
public static final String CITY_NAME = "city_name";
@BindView(R.id.header)
ViewGroup header;
@BindView(R.id.city_name)
TextView cityName;
@BindView(R.id.weather_info)
TextView weatherInfo;
@BindView(R.id.air_quality)
TextView airQuality;
@BindView(R.id.temperature)
TextView temperature;
@BindView(R.id.recyclerView)
RecyclerView recyclerView;
private WeatherDetailFragmentPresenterApi presenter; //依賴(lài)Presenter的抽象
private WeatherData data;
private FutureWeathersAdapter adapter;
private int totalDy;
private int alphaReferenceValue;
public static BaseFragment newInstance(String cityName) { //用靜態(tài)方法創(chuàng)建Fragment
WeatherDetailFragment instance = new WeatherDetailFragment();
Bundle args = new Bundle();
args.putString(CITY_NAME, cityName); //儲(chǔ)存需要顯示的地區(qū)名字在Fragment的Argument中
instance.setArguments(args);
return instance;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_weather_detail, container, false);
ButterKnife.bind(this, rootView);
presenter = new WeatherDetailFragmentPresenter(this); //創(chuàng)建Fragment的Presenter
initData();
initView();
addListener();
return rootView;
}
@Override
protected void initData() {
String cityName = getArguments().getString(CITY_NAME);
presenter.getWeatherData(cityName); //請(qǐng)求天氣數(shù)據(jù)
}
@Override
protected void initView() {
//看上面效果圖,我們只需要使用LinearLayoutManager就可以了
recyclerView.setLayoutManager(
new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
recyclerView.setItemAnimator(new DefaultItemAnimator());
}
@Override
protected void addListener() {
listenRecyclerView();
temperature.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
computeAlphaReferenceValue();
temperature.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
private void computeAlphaReferenceValue() {
//下面是在計(jì)算設(shè)置溫度TextView的Alpha值的參考值胁塞,效果是在RecyclerView的第一個(gè)Item滑動(dòng)到溫度TextView的1/8時(shí)咏尝,溫度TextView剛好完全透明
int temperatureY = temperature.getBottom();
int temperatureHeight = temperature.getMeasuredHeight();
int recyclerViewPaddingTop = recyclerView.getPaddingTop();
alphaReferenceValue = recyclerViewPaddingTop - temperatureY + temperatureHeight / 8;
}
private void listenRecyclerView() {
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
totalDy -= dy; //記錄RecyclerView滑動(dòng)的距離压语,上滑為負(fù),下滑為正
float translationY = (float) (totalDy * 0.3); //取滑動(dòng)距離的30%來(lái)移動(dòng)上半部分View才能造成層次感
header.setTranslationY(translationY); //設(shè)置整個(gè)上半部分View的TranslationY编检,實(shí)現(xiàn)圖中的滑動(dòng)效果胎食。
//translationY初始值為0,負(fù)值向上移動(dòng)蒙谓,正值向下移動(dòng)斥季,與Android坐標(biāo)系的方向是一致的
float alpha = 1 - (float) (Math.abs(totalDy * 0.3)) / alphaReferenceValue;
temperature.setAlpha(alpha); //設(shè)置Alpha值
super.onScrolled(recyclerView, dx, dy);
}
});
}
@Override
protected BasePresenter getPresenter() {
return presenter;
}
@Override
public void onWeatherDataUpdate(WeatherData data) {
if (data != null) {
updateView(data.getData());
}
}
private void updateView(WeatherData.Data data) {
setHeaderView(data);
setRecyclerView(data);
}
private void setHeaderView(WeatherData.Data data) {
String cityName = data.getRealtime().getCity_name();
this.cityName.setText(cityName);
String weatherInfo = data.getRealtime().getWeather().getInfo();
this.weatherInfo.setText(weatherInfo);
String airQualityStrFormat = getString(R.string.air_quality);
String airQuality = String.format(airQualityStrFormat, data.getPm25().getPm25().getQuality());
this.airQuality.setText(airQuality);
String temperatureFormat = getString(R.string.temperature);
String temperature =
String.format(temperatureFormat, data.getRealtime().getWeather().getTemperature());
this.temperature.setText(temperature);
}
private void setRecyclerView(WeatherData.Data data) {
if (data == null) {
return;
}
if (adapter == null) {
recyclerView.setAdapter(new FutureWeathersAdapter(getActivity(), data)); //在這里才創(chuàng)建RecyclerView的Adapter
} else {
adapter.updateData(data);
}
}
}
由于篇幅問(wèn)題训桶,本篇先講到這累驮。后面的文章中我們?cè)谝黄鹜瓿蒄ragment的Presenter、Model舵揭,以及編寫(xiě)RecyclerView的Adapter谤专。
本項(xiàng)目已上傳至GitHub,詳細(xì)源碼請(qǐng)到GitHub查看午绳。