我的全部文章整理在此篇,將陸續更新收錄:知無涯,行者之路莫言終(個人編程之路)java
擁有生命週期,含有視圖,可視可交互的界面 。 本文源碼可見此處android
1.Fragment和Activity生命週期的測試
--- Fragment和Activity生命週期
--- Fragment和Fragment切換時生命週期
--- Fragment與嵌套的子Fragment的生命週期
2.Fragment和Activity或其餘Fragment數據傳遞
--- Activity --> Fragment
--- Fragment --> Activity
--- Fragment --> Fragment
3.Fragment和ViewPager的結合以及懶加載的實現
4.Fragment中如何載入子Fragment
複製代碼
setUserVisibleHint(boolean isVisibleToUser)
|--- 第一個回調函數(多Fragment時),isVisibleToUser用戶是否可見
onCreate(Bundle savedInstanceState):
|--- Fragment初始化時
onAttach(Context context):
|--- Fragment與Context已經綁定時
View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
|--- 建立Fragment的佈局時(加載佈局和findViewById,不建議執行耗時的操做)
onViewCreated(View view, @Nullable Bundle savedInstanceState)
|--- 當視圖建立完成
onActivityCreated( Bundle savedInstanceState)
|--- 與Fragment綁定的Activity的onCreate方法已經執行完成並返回(能夠進行與Activity交互的UI操做)
onViewStateRestored(Bundle savedInstanceState)
|--- 通知fragment,該視圖層已保存
onStart()
|--- 界面已經可見
onAttachFragment()
|--- 有子Fragment被添加時回調
onResume()
|--- 界面已經可交互
onPause()
|--- 界面已經可見不可交互
onStop()
|--- 界面不可見
onSaveInstanceState(Bundle outState)
|--- 保存對象狀態
onDestroyView()
|--- 銷燬與Fragment有關的視圖,但未與Activity解除綁定
onDestroy()
|--- 銷燬Fragment
onDetach()
|--- 解除與Activity
複製代碼
2019-04-26 16:53:27.702: LifeCycleActivity--onCreate:
2019-04-26 16:53:27.704: Fragment -卍卍卍卍卍卍卍- onAttach:
2019-04-26 16:53:27.704: Fragment -卍卍卍卍卍卍卍- onCreate:
2019-04-26 16:53:27.704: Fragment -卍卍卍卍卍卍卍- onCreateView:
2019-04-26 16:53:27.711: Fragment -卍卍卍卍卍卍卍- onViewCreated:
2019-04-26 16:53:27.711: Fragment -卍卍卍卍卍卍卍- onActivityCreated:
2019-04-26 16:53:27.711: Fragment -卍卍卍卍卍卍卍- onViewStateRestored:
2019-04-26 16:53:27.714: LifeCycleActivity--onStart:
2019-04-26 16:53:27.715: Fragment -卍卍卍卍卍卍卍- onStart:
2019-04-26 16:53:27.720: LifeCycleActivity--onResume:
2019-04-26 16:53:27.720: Fragment -卍卍卍卍卍卍卍- onResume:
複製代碼
2019-04-26 17:35:30.611: Fragment -卍卍卍卍卍卍卍- onPause:
2019-04-26 17:35:30.611: LifeCycleActivity--onPause:
2019-04-26 17:35:31.342: Fragment -卍卍卍卍卍卍卍- onSaveInstanceState:
2019-04-26 17:35:31.344: LifeCycleActivity--onSaveInstanceState:
2019-04-26 17:35:31.345: Fragment -卍卍卍卍卍卍卍- onStop:
2019-04-26 17:35:31.346: LifeCycleActivity--onStop:
複製代碼
2019-04-26 17:41:28.254: LifeCycleActivity--onRestart:
2019-04-26 17:41:28.255: LifeCycleActivity--onStart:
2019-04-26 17:41:28.256: Fragment -卍卍卍卍卍卍卍- onStart:
2019-04-26 17:41:28.258: LifeCycleActivity--onResume:
2019-04-26 17:41:28.258: Fragment -卍卍卍卍卍卍卍- onResume:
複製代碼
2019-04-26 18:12:25.328: Fragment -卍卍卍卍卍卍卍- onPause:
2019-04-26 18:12:25.328: LifeCycleActivity--onPause:
2019-04-26 18:12:25.864: Fragment -卍卍卍卍卍卍卍- onStop:
2019-04-26 18:12:25.865: LifeCycleActivity--onStop:
2019-04-26 18:12:25.865: Fragment -卍卍卍卍卍卍卍- onDestroyView:
2019-04-26 18:12:25.867: Fragment -卍卍卍卍卍卍卍- onDestroy:
2019-04-26 18:12:25.867: Fragment -卍卍卍卍卍卍卍- onDetach:
2019-04-26 18:12:25.868: LifeCycleActivity--onDestroy:
複製代碼
後者先建立,前者再銷燬git
2019-04-26 20:10:20.095 : Fragment -卍卍卍卍卍卍卍- onAttach:
2019-04-26 20:10:20.095 : Fragment -卍卍卍卍卍卍卍- onCreate:
2019-04-26 20:10:20.095 : Fragment -卍卍卍卍卍卍卍- onCreateView:
2019-04-26 20:10:20.112 : Fragment -卍卍卍卍卍卍卍- onViewCreated:
2019-04-26 20:10:20.112 : Fragment -卍卍卍卍卍卍卍- onActivityCreated:
2019-04-26 20:10:20.113 : Fragment -卍卍卍卍卍卍卍- onViewStateRestored:
2019-04-26 20:10:20.113 : Fragment -卍卍卍卍卍卍卍- onStart:
2019-04-26 20:10:20.115 : Fragment -卍卍卍卍卍卍卍- onResume:
2019-04-26 20:10:20.115 : Fragment -卍卍卍卍卍卍卍- onPause:
2019-04-26 20:10:20.115 : Fragment -卍卍卍卍卍卍卍- onStop:
2019-04-26 20:10:20.116 : Fragment -卍卍卍卍卍卍卍- onDestroyView:
2019-04-26 20:10:20.118 : Fragment -卍卍卍卍卍卍卍- onDestroy:
2019-04-26 20:10:20.118 : Fragment -卍卍卍卍卍卍卍- onDetach:
複製代碼
注
卍卍卍卍卍卍卍
表示父,☯☯☯☯☯☯☯☯表示子
github
---->[打開時]-----------先父後子,注意在onStart以後子Fragment開始attach---------------
2019-04-27 08:36:44.332 : Fragment -卍卍卍卍卍卍卍- onAttach:
2019-04-27 08:36:44.332 : Fragment -卍卍卍卍卍卍卍- onCreate:
2019-04-27 08:36:44.346 : Fragment -卍卍卍卍卍卍卍- onCreateView:
2019-04-27 08:36:44.351 : Fragment -卍卍卍卍卍卍卍- onViewCreated:
2019-04-27 08:36:44.351 : Fragment -卍卍卍卍卍卍卍- onActivityCreated:
2019-04-27 08:36:44.351 : Fragment -卍卍卍卍卍卍卍- onViewStateRestored:
2019-04-27 08:36:44.352 : Fragment -卍卍卍卍卍卍卍- onStart:
2019-04-27 08:36:44.353 : Fragment -☯☯☯☯☯☯☯☯- onAttach:
2019-04-27 08:36:44.353 : Fragment -卍卍卍卍卍卍卍- onAttachFragment: <--- 注意這裏
2019-04-27 08:36:44.353 : Fragment -☯☯☯☯☯☯☯☯- onCreate:
2019-04-27 08:36:44.354 : Fragment -☯☯☯☯☯☯☯☯- onCreateView:
2019-04-27 08:36:44.358 : Fragment -☯☯☯☯☯☯☯☯- onViewCreated:
2019-04-27 08:36:44.358 : Fragment -☯☯☯☯☯☯☯☯- onActivityCreated:
2019-04-27 08:36:44.358 : Fragment -☯☯☯☯☯☯☯☯- onViewStateRestored:
2019-04-27 08:36:44.358 : Fragment -☯☯☯☯☯☯☯☯- onStart:
2019-04-27 08:36:44.365 : Fragment -卍卍卍卍卍卍卍- onResume:
2019-04-27 08:36:44.365 : Fragment -☯☯☯☯☯☯☯☯- onResume:
---->[退出時]-----------先子後父交替回調---------------
2019-04-27 08:44:13.697 : Fragment -☯☯☯☯☯☯☯☯- onPause:
2019-04-27 08:44:13.698 : Fragment -卍卍卍卍卍卍卍- onPause:
2019-04-27 08:44:14.639 : Fragment -☯☯☯☯☯☯☯☯- onStop:
2019-04-27 08:44:14.639 : Fragment -卍卍卍卍卍卍卍- onStop:
2019-04-27 08:44:14.654 : Fragment -☯☯☯☯☯☯☯☯- onDestroyView:
2019-04-27 08:44:14.654 : Fragment -卍卍卍卍卍卍卍- onDestroyView:
2019-04-27 08:44:14.655 : Fragment -☯☯☯☯☯☯☯☯- onDestroy:
2019-04-27 08:44:14.655 : Fragment -☯☯☯☯☯☯☯☯- onDetach:
2019-04-27 08:44:14.655 : Fragment -卍卍卍卍卍卍卍- onDestroy:
2019-04-27 08:44:14.655 : Fragment -卍卍卍卍卍卍卍- onDetach:
複製代碼
實現:在Activity傳入顏色數據,在Fragment中接收數據並使用編程
---->[在Activity中設置Fragment的參數]-----------------------------------
FragmentManager fm = getFragmentManager();//1.獲取FragmentManager
FragmentTransaction ft = fm.beginTransaction();//2.fm開啓事務
Bundle bundle = new Bundle();//建立Bundle對象
bundle.putString("data", "#ff0000");//爲bundle賦值
BoxFragment boxFragment = new BoxFragment();
boxFragment.setArguments(bundle);//爲Fragment設置Arguments
//3.動態添加 (控件id,fragment對象,tag)
ft.add(R.id.fl_fragmemt_content, new ResultFragment());
ft.commit();//4.提交事務
---->[在BoxFragment中讀取參數並使用]-----------------------------------
TextView txt = view.findViewById(R.id.id_tv_txt);
Bundle bundle = getArguments();
if (bundle != null) {
String result = bundle.getString("color");
view.setBackgroundColor(Color.parseColor(result));
txt.setText(result);
}
複製代碼
這能夠稍微改進一下:將Bundle在Fragment中建立,經過一個靜態方法+入參建立Fragment數組
---->[在BoxFragment中添加靜態方法]-----------------------------------
public static BoxFragment newInstance(String color) {
BoxFragment fragment = new BoxFragment();
Bundle bundle = new Bundle();
bundle.putString("color", color);
fragment.setArguments(bundle);
return fragment;
}
---->[在Activity中建立對象]-----------------------------------
BoxFragment boxFragment = BoxFragment.newInstance("#238AF8")
複製代碼
好處在於方便建立Fragment,好比加個紅色:bash
BoxFragment radFragment = BoxFragment.newInstance("#ff0000")
複製代碼
點擊Fragment內的View,Fragment將顏色值傳給Activityapp
---->[在BoxFragment中添加回調接口]-----------------------------------
public interface OnDataSend {
void send(String data);
}
private OnDataSend mOnDataSend;
public void setmOnDataSend(OnDataSend mOnDataSend) {
this.mOnDataSend = mOnDataSend;
}
---->[在BoxFragment#onViewCreated觸發回調]-----------------------------------
txt.setOnClickListener(v -> {
if (mOnDataSend != null) {
mOnDataSend.send(txt.getText().toString().toUpperCase());
}
});
---->[在Activity中設置回調]-----------------------------------
radFragment.setmOnDataSend {
id_tv_result.text = it
}
複製代碼
---->[在Activity中添加公共方法]-----------------------------------
fun setData(s: String) {
id_tv_result.text = s
}
---->[在BoxFragment#onViewCreated獲取宿主對象並調用方法]-----------
txt.setOnClickListener(v -> {//這裏強轉最好加個instanceof判斷
LifeCycleActivity activity = (LifeCycleActivity) getActivity();
activity.setData(txt.getText().toString().toUpperCase());
});
複製代碼
挺方便的,不過這對宿主Activity增長了負擔,不須強轉成宿主類型,感受有點狹隘
感受新建一個接口用來規定數據傳輸的方法,應該會好一些,就像正規軍和游擊隊吧...ide
//數據傳送的接口(固然你能夠定義不少接口,這裏只舉個例子)
public interface IBoxSender {
void setData(String data);
}
---->[在Activity實現接口]-----------------------------------
class LifeCycleActivity : AppCompatActivity(), IBoxSender {
...
override fun setData(s: String) {
id_tv_result.text = s
}
}
---->[在BoxFragment#onViewCreated獲取宿主對象並調用方法]-----------
txt.setOnClickListener(v -> {//這裏強轉最好加個instanceof判斷
IBoxSender sender = (IBoxSender) getActivity();
sender.setData(txt.getText().toString().toUpperCase());
});
//從我我的審美來講,這樣彷佛更優雅一點
複製代碼
固然你也能夠將控件直接傳給Fragment,但感受太無聊了,就不說了函數
紅色Fragment在點擊時,將本身的顏色值傳送給藍色Fragment,藍色Fragment接收後變色
很容易想到分兩步:紅色Fragment --> Activity , Activity --> 藍色Fragment
//數據傳送的接口
public interface IBoxSender {
void setData(String data);
void update(String color); //增長接口
}
---->[在Activity實現接口方法]-----------------------------------
override fun update(color: String) {
fragmentManager.beginTransaction()
.replace(R.id.fl_title, BoxFragment.newInstance(color))
.commit()
}
---->[在BoxFragment#onViewCreated獲取宿主對象並調用方法]-----------
txt.setOnClickListener(v -> {//這裏強轉最好加個instanceof判斷
IBoxSender sender = (IBoxSender) getActivity();
sender.update(txt.getText().toString());
});
複製代碼
這是曾經讓我疑惑的一點:構造函數入參來傳參不是挺好的嗎?可是:
貌似AS 不給咱們用構造,須要經過Fragment#setArguments(Bundle)
來傳參
若是我任性,偏要用呢?----雖然畫紅線可是仍是運行仍是能跑起來的,效果也沒有差異, 因而乎,問題來了: 爲何谷歌的大佬不推薦咱們在Fragment中使用構造函數呢?
|--- 在旋轉屏幕時:Fragment將面臨 銷燬+重建 ,但測試中Fragment並無什麼變化
|--- 重建的Fragment是系統幫咱們作的,那它怎麼還原剛纔的參數呢(顏色)?一個詞 :Bundle
|--- 下面是Fragment中建立ragment靜態方法,其中用反射實例化了無參構造,並將配置參數進行還原
|--- 因此爲何不能自定義Fragment的構造函數不言而喻:Fragment銷燬+重建只會使用無參構造
public static Fragment instantiate(Context context, String fname) {
return instantiate(context, fname, null);
}
public static Fragment instantiate(Context context, String fname, @Nullable Bundle arg)
try {
Class<?> clazz = sClassMap.get(fname);
if (clazz == null) {
// Class not found in the cache, see if it's real, and try to add it clazz = context.getClassLoader().loadClass(fname); if (!Fragment.class.isAssignableFrom(clazz)) { throw new InstantiationException("Trying to instantiate a class " + f + " that is not a Fragment", new ClassCastException()); } sClassMap.put(fname, clazz); } Fragment f = (Fragment) clazz.getConstructor().newInstance(); <--- 注意這裏用的是無參構造建立f對象 if (args != null) { <--- 當Binder對象非空時,會將args再給f對象,也就還原了配置 args.setClassLoader(f.getClass().getClassLoader()); f.setArguments(args); } return f; } catch (ClassNotFoundException e) { ..... } } 複製代碼
你能夠試一下:使用Fragment一參構造,而後轉屏時,程序會崩掉,因此我們仍是別任性...
public class ViewPagerActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_viewpager);
ViewPager viewPager = findViewById(R.id.id_vp);
//顏色數組
String[] colors = new String[]{"#F73815", "#FAA43E", "#FCE73C", "#51F81E", "#1E94F8", "#8CE9F4", "#B24DF4"};
//詳情數組
String[] info = new String[]{"紅", "橙", "黃", "綠", "藍", "靛", "紫"};
viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {//設置FragmentPagerAdapter
@Override
public Fragment getItem(int position) {
return BoxFragment.newInstance(colors[position],info[position]);
}
@Override
public int getCount() {
return colors.length;
}
});
}
}
複製代碼
打開時
isVisibleToUser
出現了,並且是最早調用的,一開始是紅色isVisibleToUser= true
總的來講就是生成了紅色和黃色兩個Fragment並對二者其進行了初始化
2019-04-26 23:12:59.444 - isVisibleToUser: 紅---false
2019-04-26 23:12:59.444 - isVisibleToUser: 橙---false
2019-04-26 23:12:59.444 - isVisibleToUser: 紅---true
2019-04-26 23:12:59.446 - onAttach: 紅
2019-04-26 23:12:59.446 - onCreate: 紅
2019-04-26 23:12:59.446 - onAttach: 橙
2019-04-26 23:12:59.446 - onCreate: 橙
2019-04-26 23:12:59.447 - onCreateView: 紅
2019-04-26 23:12:59.455 - onViewCreated: 紅
2019-04-26 23:12:59.456 - onActivityCreated: 紅
2019-04-26 23:12:59.456 - onViewStateRestored: 紅
2019-04-26 23:12:59.456 - onStart: 紅
2019-04-26 23:12:59.456 - onResume: 紅
2019-04-26 23:12:59.457 - onCreateView: 橙
2019-04-26 23:12:59.463 - onViewCreated: 橙
2019-04-26 23:12:59.463 - onActivityCreated: 橙
2019-04-26 23:12:59.463 - onViewStateRestored: 橙
2019-04-26 23:12:59.464 - onStart: 橙
2019-04-26 23:12:59.464 - onResume: 橙
複製代碼
滑到下一屏()橙色
橙色和用戶見面了,因此橙色的
isVisibleToUser= true
這時對黃色Fragment(即下一頁)進行了初始化,俗稱預加載
2019-04-26 23:16:53.738 - isVisibleToUser: 黃---false
2019-04-26 23:16:53.738 - isVisibleToUser: 紅---false
2019-04-26 23:16:53.738 - isVisibleToUser: 橙---true
2019-04-26 23:16:53.739 - onAttach: 黃
2019-04-26 23:16:53.740 - onCreate: 黃
2019-04-26 23:16:53.743 - onCreateView: 黃
2019-04-26 23:16:53.766 - onViewCreated: 黃
2019-04-26 23:16:53.767 - onActivityCreated: 黃
2019-04-26 23:16:53.767 - onViewStateRestored: 黃
2019-04-26 23:16:53.767 - onStart: 黃
2019-04-26 23:16:53.767 - onResume: 黃
複製代碼
滑到下一屏(黃色)
黃色和用戶見面了,因此黃色的
isVisibleToUser= true
紅色(上上頁)銷燬了,綠色(下一頁)進行初始化
2019-04-26 23:19:38.122 - isVisibleToUser: 綠---false
2019-04-26 23:19:38.123 - isVisibleToUser: 橙---false
2019-04-26 23:19:38.123 - isVisibleToUser: 黃---true
2019-04-26 23:19:38.124 - onAttach: 綠
2019-04-26 23:19:38.125 - onCreate: 綠
2019-04-26 23:19:38.129 - onPause: 紅
2019-04-26 23:19:38.130 - onStop: 紅
2019-04-26 23:19:38.132 - onDestroyView: 紅
2019-04-26 23:19:38.140 - onCreateView: 綠
2019-04-26 23:19:38.154 - onViewCreated: 綠
2019-04-26 23:19:38.155 - onActivityCreated: 綠
2019-04-26 23:19:38.155 - onViewStateRestored: 綠
2019-04-26 23:19:38.155 - onStart: 綠
2019-04-26 23:19:38.156 - onResume: 綠
複製代碼
以後都是類似的,當前頁的上上頁(若是有的話)會被銷燬,下一頁(若是有的話)會被初始化到onResume
也就是不想要預加載,畢竟有些時候不想提早爲之後的消耗買單
但Fragment仍是會建立的
)private boolean initialization; // 界面是否已初始化完畢
private boolean isVisibleToUser; // 是否對用戶可見
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
this.isVisibleToUser = isVisibleToUser;
lazyLoad();
}
private void lazyLoad() {
if (initialization && isVisibleToUser) {
loadData();
}
}
/**
* 核心加載方法(可抽象)
*/
private void loadData() {
Log.e("loadData", "initData: "+info);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
Log.e(TAG, "Fragment -卍卍卍卍卍卍卍- onActivityCreated: " + info);
initialization = true;
lazyLoad();
super.onActivityCreated(savedInstanceState);
}
複製代碼
預加載是ViewPager的鍋,雖然能夠設置預加載多個,可是不能不預加載...
鍋是這行代碼的private static final int DEFAULT_OFFSCREEN_PAGES = 1;// 默認的加載頁面
因此自定義一個View 將ViewPager代碼拷貝一份,上面哪行改爲0,代碼不貼了,詳見此處:
可是,考慮到兼容問題,仍是用懶加載Fragment比較好,畢竟建立兩個對象也沒什麼大不了,加載數據限制住就OK了
既然提到ViewPager就簡單說一下吧
|--- 使用方式 ------------------------------------------
viewPager.setPageTransformer(true, new VPTFadeScale());
public class VPTFadeScale implements ViewPager.PageTransformer {
private static float MIN_SCALE = 0.7f;
//A==>B A的position 0==>-1 B的position 1==>0
@Override
public void transformPage(View page, float position) {
int width = page.getWidth();
int height = page.getHeight();
if (position < -1) {//非A、B頁
page.setAlpha(1);
} else if (position <= 0) {//A頁的動畫
page.setAlpha(1 + position * 2);
page.setScaleX(1);
page.setScaleY(1);
page.setPivotX(0);
page.setPivotY(height / 2);
page.setRotationX(-100 * position);
page.setRotationY(-100 * position);
} else if (position <= 1) {//B頁的動畫
page.setAlpha(1 - position);
page.setTranslationX(width * (-position));
// 0.75~1
float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position));
page.setScaleX(scaleFactor);
page.setScaleY(scaleFactor);
}
}
}
複製代碼
根據滑動時的參數能夠作一些好玩的事
//[]ViewPager滑動監聽
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
/**
* 當頁面滑動過程當中的回調
* @param position 當前滑動頁面的位置
* @param positionOffset 下一頁在當前頁所佔的寬度百分比
* @param positionOffsetPixels 下一頁在當前頁所佔的寬度像素值
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels
Log.e(TAG, "onPageScrolled: " + "position==>"
+ position + "----positionOffset==>"
+ positionOffset + "----positionOffsetPixels" + positionOffsetPixels);
}
/**
* 某個頁面被選中(從0計數) 翻頁成功纔會調用
* @param position 翻頁後的視圖在集合中位置
*/
@Override
public void onPageSelected(int position) {
Log.e(TAG, "onPageSelected: " + position);
}
/**
* 頁面狀態發生變化的回調 1 滑動開始到手指離開前 2 手指離開後到結束之間 0 滑動結束
* @param state 狀態
*/
@Override
public void onPageScrollStateChanged(int state) {
Log.e(TAG, "onPageScrollStateChanged: " + state);
}
});
複製代碼
關鍵是經過
getChildFragmentManager
獲取管理器,注意要在onStart或以後獲取
---->[PagerFragment]------------一個孩子----------
@Override
public void onStart() {
SideFragment fragment = new SideFragment();
getChildFragmentManager()
.beginTransaction()
.add(R.id.fl_side, fragment)
.show(fragment)
.commit();
}
---->[PagerFragment]------------多個孩子----------
@Override
public void onStart() {
super.onStart();
SideFragment side = new SideFragment();
BoxFragment title = BoxFragment.newInstance("#eeeeee");
BoxFragment footer = BoxFragment.newInstance("#eeeeee");
getChildFragmentManager()
.beginTransaction()
.add(R.id.fl_side, side)
.add(R.id.fl_title, title)
.add(R.id.fl_bottom, footer)
.show(title)
.show(side)
.show(footer)
.commit();
}
複製代碼
效果是點擊主Fragment側邊欄會顯示/隱藏切換
private boolean sideShowing = true;
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
Log.e(TAG, "Fragment -卍卍卍卍卍卍卍- onViewCreated: ");
super.onViewCreated(view, savedInstanceState);
view.setOnClickListener(v -> {
if (sideShowing) {
hideAt(0);
} else {
showAt(0);
}
sideShowing = !sideShowing;
});
}
public void hideAt(int i) {
List<Fragment> fragments = getChildFragmentManager().getFragments();
getChildFragmentManager().beginTransaction().hide(fragments.get(i)).commit();
}
public void showAt(int i) {
List<Fragment> fragments = getChildFragmentManager().getFragments();
getChildFragmentManager().beginTransaction().show(fragments.get(i)).commit();
}
複製代碼
view.setOnLongClickListener(v -> {
Intent i = new Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, 0);// 設定結果返回
return false;
});
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (data != null) {
switch (requestCode) {
case 0:
//打開相冊並選擇照片,這個方式選擇單張
// 獲取返回的數據,這裏是android自定義的Uri地址
Uri selectedImage = data.getData();
Log.e("startActivityForResult", "startActivityForResult: " + selectedImage);
break;
}
}
}
複製代碼
注意申請時用
XXXFragment.this.requestPermissions
不然onRequestPermissionsResult
沒法回調
private static final int PERMISSION_REQ_ID = 22;
private static final String[] REQUESTED_PERMISSIONS = {
Manifest.permission.RECORD_AUDIO,//錄音權限
Manifest.permission.CAMERA,//相機權限
Manifest.permission.WRITE_EXTERNAL_STORAGE//SD卡寫權限
};
view.setOnClickListener(v -> {//點擊申請權限
if (checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID) &&
checkSelfPermission(REQUESTED_PERMISSIONS[1], PERMISSION_REQ_ID) &&
checkSelfPermission(REQUESTED_PERMISSIONS[2], PERMISSION_REQ_ID)) {
//執行到此處說明已有權限成功
Toast.makeText(getActivity(), "已有權限成功", Toast.LENGTH_SHORT).show();
}
});
/**
* 檢查權限的方法
*
* @param permission 權限
* @param requestCode 請求碼
* @return 是否擁有權限
*/
public boolean checkSelfPermission(String permission, int requestCode) {
if (ContextCompat.checkSelfPermission(getActivity(), permission)
!= PackageManager.PERMISSION_GRANTED) {
//發送權限請求
PagerFragment.this.requestPermissions(REQUESTED_PERMISSIONS, requestCode); <-- 注意申請時用XXXFragment.this.
return false;
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSION_REQ_ID: {//請求碼
if (grantResults[0] != PackageManager.PERMISSION_GRANTED ||
grantResults[1] != PackageManager.PERMISSION_GRANTED ||
grantResults[2] != PackageManager.PERMISSION_GRANTED) {
//三個權限有任意的未被容許,彈吐司,退出
Toast.makeText(getActivity(), "用戶沒有容許權限", Toast.LENGTH_SHORT).show();
getActivity().finish();
break;
}
Log.e(TAG, "onRequestPerm: OK");
break;
}
}
}
複製代碼
[1].將整個界面的責任碎片化,分散到各個部分,緩解Activity的負擔
[2].方便修改/更新:那個地方出現問題/須要更新界面樣式,能夠直接去找對應的Fragment,而不是像之前在Activity裏大海撈針
[3].方便複用: Fragment遷移很方便,哪裏須要哪裏搬。遇到差很少的需求,改改就能用了。
[4].運行中能夠動態地移除、加入、交換,使用靈活
[5].能夠`startActivityForResult + onActivityResult`,有目的的開啓一個Activity
[6].能夠動態申請權限 requestPermissions + onRequestPermissionsResult
[7].ViewPager和Fragment結合容易實現切換效果
複製代碼