由于一直在小公司待著,所做的安卓開發(fā)工作都是面對的工廠內(nèi)部使用,所以對于界面的要求很低?,F(xiàn)在突然想要換到互聯(lián)網(wǎng)公司去工作,面試的過程中碰了很多的壁,因為對于傳統(tǒng)生產(chǎn)線上的安卓產(chǎn)品和互聯(lián)網(wǎng)的安卓產(chǎn)品有很大的不同,傳統(tǒng)產(chǎn)線的產(chǎn)品要求高性能,對于界面要求則是盡可能的簡單。但是對于互聯(lián)網(wǎng)產(chǎn)品則側(cè)重點在界面效果豐富強大?;谶@種,所以在后面的開發(fā)中使用一些Material Design提供的控件開發(fā)。以此來記錄自己使用這些控件時的困惑,然后在學(xué)習(xí)該控件的實現(xiàn)。
TabLayout控件是在android.support.design.widget 包中,首先使用的時候需要在gradle中引入'com.android.support:design:28.0.0'。
我在學(xué)習(xí)使用的過程中,查看別人的寫法有說design包25以下會有問題,所以我直接使用最新的28版本,至于25以下是否有問題則沒有測試過,以下筆記內(nèi)容在我使用過程當(dāng)中,如果有用到什么隨時添加相應(yīng)的使用內(nèi)容。
屬性tabmode是當(dāng)你的tab頁在鋪滿屏幕的時候可以選擇的模式scrollable是表示可滑動的,fixed則表示不可滑動。
其中tabBackground是設(shè)置你的TabLayout整個控件的背景,
tabIndicatorColor則是設(shè)置下劃線的顏色,tabIndicatorHeight設(shè)置下劃線的高度,tabSelectedTextColor則是設(shè)置選中的文字的渲染的顏色。
以下是我activity頁面布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<android.support.design.widget.TabLayout
android:id="@+id/tl"
android:layout_marginLeft="@dimen/dp_15"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:tabBackground="@color/white"
app:tabIndicatorColor="@color/work_flow_tabunderline"
app:tabIndicatorHeight="4dp"
app:tabSelectedTextColor="@color/black"
android:layout_marginBottom="@dimen/dp_11"
>
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
</LinearLayout>
activity的界面邏輯
public class TestActivity extends AppCompatActivity {
ViewPager vp;
VPAdapter adapter;
List<Fragment> list=new ArrayList<>();
Fragment1 fragment1;
Fragment2 fragment2;
Fragment3 fragment3;
TabLayout tl;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test1);
vp=findViewById(R.id.vp);
tl=findViewById(R.id.tl);
FragmentManager fm=this.getSupportFragmentManager();
adapter=new VPAdapter(fm,list);
vp.setAdapter(adapter);
initView();
tl.setupWithViewPager(vp);
}
public void initView()
{
fragment1=new Fragment1();
fragment2=new Fragment2();
fragment3=new Fragment3();
list.add(fragment1);
list.add(fragment2);
list.add(fragment3);
adapter.notifyDataSetChanged();
}
}
這里的 tl.setupWithViewPager(vp);方法是將ViewPager和TabLayout關(guān)聯(lián)起來,但是當(dāng)關(guān)聯(lián)之后要重寫viewpager里適配器的一個方法才能顯示tablayout的tab頁文字。以下是viewpager的adapter適配器里的代碼
public class VPAdapter extends FragmentPagerAdapter {
List<Fragment> list;
String[] title=new String[]{"待辦","已辦","委托"};
public VPAdapter(FragmentManager fm, List<Fragment> list) {
super(fm);
this.list = list;
}
@Override
public Fragment getItem(int i) {
return list.get(i);
}
@Override
public int getCount() {
return list.size();
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return title[position];
}
}
其中g(shù)etPageTitle(int position)就是當(dāng)viewpager和tablayout進行關(guān)聯(lián)的時候tablayout的tab頁的文字信息就是由該方法來的。
Fragment的頁面布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/srl"
android:layout_marginTop="@dimen/dp_24"
android:layout_marginLeft="@dimen/dp_15"
android:layout_marginRight="@dimen/dp_15"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rvInfo"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
這里的3個fragment共用這一個布局,fragment代碼相同,這里貼出一個fragment的代碼
public class Fragment1 extends MVPBaseFragment<WorkPresent,WorkConstract.IWorkView> implements WorkConstract.IWorkView
,SwipeRefreshLayout.OnRefreshListener {
EditText etSearch;
SwipeRefreshLayout srl;
RecyclerView rvInfo;
WorkAdapter adapter;
List<Work> list=new ArrayList<>();
LinearLayoutManager linearLayoutManager;
@Override
protected void initData() {
list.clear();
mPresent.getData();//調(diào)用接口
}
@Override
protected void initView(View view) {
srl=view.findViewById(R.id.srl);
rvInfo=view.findViewById(R.id.rvInfo);
etSearch=view.findViewById(R.id.etSearch);
adapter=new WorkAdapter(R.layout.item_work,list);
linearLayoutManager=new LinearLayoutManager(getActivity());
rvInfo.setLayoutManager(linearLayoutManager);
rvInfo.setAdapter(adapter);
srl.setColorSchemeColors(getResources().getColor(R.color.colorAccent));
srl.setOnRefreshListener(this);
}
@Override
protected WorkPresent creatPresent(MVPBaseFragment<WorkPresent, WorkConstract.IWorkView> workPresentIWorkViewMVPBaseFragment) {
return new WorkPresent();
}
@Override
protected View initLayout(LayoutInflater inflater, ViewGroup container) {
View view=inflater.inflate(R.layout.frg_work,container,false);
return view;
}
@Override
public void showLoading() {
}
@Override
public void hideLoading() {
}
@Override
public void showError(String message) {
}
@Override
public void getData() {
mPresent.getData();
}
@Override
public String getSearch() {
return etSearch.getText().toString();
}
@Override
public void setSearch(String str) {
etSearch.setText(str);
}
@Override
public void onRefresh() {
list.clear();
mPresent.getData();
}
public BaseQuickAdapter getAdapter()
{
return adapter;
}
}
這里使用的mvp模式做的不去管里面的邏輯實現(xiàn),這里調(diào)用接口和數(shù)據(jù)的業(yè)務(wù)處理在present里面。
當(dāng)我在里面切換fragment的時候,viewpager里的fragmentAdapter是保存了fragment的狀態(tài)的,也就是說這里的fragment是重用的,不是每次切換的時候重新創(chuàng)建的fragment,所以在initData初始化數(shù)據(jù)的時候需要清空數(shù)據(jù)源list,在一開始做的時候沒有在initData里面調(diào)用list.clean()清空,我在切換viewpager看到里面的數(shù)據(jù)源的數(shù)量一直在不斷的遞增,所以啟用調(diào)試模式查看fragment在viewpager里面切換的時候fragment對象沒有重新創(chuàng)建,但是adapter在切換的時候?qū)ο蟾淖兞耍琹ist的對象也是不變的,調(diào)試到這里的時候就可以確定了fragment是重用的,該對象的屬性對象list的指針指向的地址不變也是同一個對象,而fragment從不可見變的可見的時候onCreateView()的聲明周期重新調(diào)用,其中initView(View view)和initData()方法是在超類(抽象類)的onCreateView()里的抽象方法,所以子類的這2個方法在onCreateView()里會重新調(diào)用,證明了adapter被重新創(chuàng)建,list和fragment被復(fù)用沒有創(chuàng)建新的對象。那么這里的解決數(shù)據(jù)個數(shù)不對的問題可以在initView()里對list實例化,不在聲明的時候?qū)嵗搶ο?,或者在initData()里面調(diào)用list.clean()方法清空數(shù)據(jù)源也能解決數(shù)據(jù)錯亂的問題。
之所以記錄上面的這個數(shù)據(jù)錯亂問題,是因為我在使用fragment的時候從來不沒有考慮過復(fù)用的問題,一直是用replace方法來替換fragment,所以習(xí)慣的這種方式之后再用到復(fù)用的時候,出現(xiàn)了數(shù)據(jù)錯亂的問題。所以記錄下,以后再用刀fragment時候在寫業(yè)務(wù)邏輯的時候要考慮復(fù)用問題對于業(yè)務(wù)的影響,第二個是優(yōu)化自己使用Fragment,盡量使用能復(fù)用的fragment對于性能的消耗要小。
以上是使用tablayout和viewpager混合使用當(dāng)中遇到的問題,以作記錄,方便自己以后查閱。