編輯:關於Android編程
碎片(Fragment)是一種可以嵌入在活動當中的UI片段,它能讓程序更加合理和充分地利用大屏幕的空間,因而在平板上應用的非常廣泛。
這是《第一行代碼》書中的介紹
想象我們正在開發一個新聞應用,其中一個界面使用ListView展示了一組新聞的標題,當點擊了其中一個標題,就打開另一個界面顯示新聞的詳細內容。如果是在手機中設計,我們可以將新聞標題列表放在一個活動中,將新聞的詳細內容放在另一個活動中,如圖所示。
可是如果在平板上也這麼設計,那麼新聞標題列表將會被拉長至填充滿整個平板的屏幕,而新聞的標題一般都不會太長,這樣將會導致界面上有大量的空白區域,如圖所示。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxpbWcgYWx0PQ=="這裡寫圖片描述" src="/uploadfile/Collfiles/20160827/20160827093239539.png" title="\" />
因此,更好的設計方案是將新聞標題列表界面和新聞詳細內容界面分別放在兩個碎片中,然後在同一個活動裡引入這兩個碎片,這樣就可以將屏幕空間充分地利用起來了,如圖所示。
Fragment的出現就是為了解決屏幕適配問題。你可以把Fragment當成Activity的一個界面的一個組成部分,甚至Activity的界面可以完全有不同的Fragment組成,而且Fragment擁有自己的生命周期和接收、處理用戶的事件,這樣就不必在Activity寫一堆控件的事件處理的代碼了。更為重要的是,你可以動態的添加、替換和移除某個Fragment。
Fragment必須依附Activity的存在,通過Activity來加載Fragment
定義一個類繼承Fragment
import android.support.v4.app.Fragment; .... public class Fragment3 extends Fragment { @Nullable //重寫onCreateView方法 @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { //通過打氣筒加載Fragment的布局 View view = inflater.inflate(R.layout.fragment3,null); return view; } }
import android.support.v4.app.Fragment;
android.app.Fragment3.0之後才有的,支持的版本太高
選擇v4包,是為了可以兼容到1.6的版本的手機,但會影響到獲取FragmentManager方式的不同
而且非常非常重要的是包含Fragment的Activity必須繼承FragmentActivity
否則你就等著報錯吧
import android.app.Fragment;
導入這個包則不需修改Activity
Fragment3的布局文件
activity的布局文件
MainActivity記得繼承FragmentActivity
import android.support.v4.app.FragmentActivity; ... public class MainActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
結果
首先給出程序運行成功的gif圖
這是一個橫豎屏切換時,切換Activity裡的Fragment的效果
這裡分別定義一個橫屏的Fragment和一個豎屏的Fragment
import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; /** * Created by Peng on 2016/8/4. */ public class Fragment1 extends Fragment { @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment1, null); return view; } }橫屏 Fragment1 布局
public class Fragment2 extends Fragment { @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment2,null); return view; } }豎屏 Fragment2布局
import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.view.WindowManager; public class MainActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //獲取手機的分辨率 WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); int width = wm.getDefaultDisplay().getWidth(); int height = wm.getDefaultDisplay().getHeight(); /** * 如果使用的不是v4包的Fragment,就要用getFragmentManager()的到管理者 * 而且FragmentManager也是用android.app.FragmentManager包 * FragmentManager fragmentManager = getFragmentManager(); */ //獲取fragment的管理者 通過上下文獲取 FragmentManager fragmentManager = getSupportFragmentManager(); //開啟事物 android.support.v4.app.FragmentTransaction beginTrasaction = fragmentManager.beginTransaction(); //判斷橫豎 if (height > width) { //豎屏 android.R.id.content 代表當前手機的窗體 beginTrasaction.replace(android.R.id.content, new Fragment1()); } else { //橫屏 beginTrasaction.replace(android.R.id.content, new Fragment2()); } //最後一步 beginTrasaction.commit(); } }
Activity的布局文件裡並不需要設置,Fragment的布局會和activity共同顯示在Activity上
你可以在Activity裡寫一些內容,內容會一直顯示出來
首先程序運行的效果
Activity的布局 activity_main.xml
bottom.xml
Fragment,這裡用的是android.app.Fragment的包,沒有用v4
的包,注意一下
import android.app.Fragment; import android.os.Bundle; import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; /** * Created by Peng on 2016/8/4. */ public class ContactFragment extends Fragment { @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view =inflater.inflate(R.layout.fragment_contact,null); return view; } }
四個Fragment的布局,這裡只寫一個,都是類似的
MainActivity
import android.app.FragmentManager; import android.app.FragmentTransaction; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private LinearLayout llLayout; private Button btnWx; private Button btnContact; private Button btnDiscover; private Button btnMe; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); llLayout = (LinearLayout) findViewById(R.id.ll_layout); //四個按鈕 微信 通訊錄 發現 我 btnWx = (Button) findViewById(R.id.btn_wx); btnContact = (Button) findViewById(R.id.btn_contact); btnDiscover = (Button) findViewById(R.id.btn_discover); btnMe = (Button) findViewById(R.id.btn_me); //設置事件 btnWx.setOnClickListener(this); btnContact.setOnClickListener(this); btnDiscover.setOnClickListener(this); btnMe.setOnClickListener(this); } @Override public void onClick(View view) { //獲取fragment的管理者 FragmentManager fragmentManager = getFragmentManager(); //開啟事物 FragmentTransaction beginTrasaction = fragmentManager.beginTransaction(); //具體判斷點擊那個按鈕 switch (view.getId()) { case R.id.btn_wx://點擊的是微信 beginTrasaction.replace(R.id.ll_layout, new WxFragment()); break; case R.id.btn_contact://點擊的是聯系人 beginTrasaction.replace(R.id.ll_layout, new ContactFragment()); break; case R.id.btn_discover://點擊的是發現 beginTrasaction.replace(R.id.ll_layout, new DiscoverFragment()); break; case R.id.btn_me://點擊的是我 beginTrasaction.replace(R.id.ll_layout, new MeFragment()); break; } beginTrasaction.commit(); } }
用replace切換顯示的Fragment,這種方法非常方便,但是這種方法不是最完美的, 下面-FragmentTransaction的方法-裡關於它的介紹
當我們通過點擊按鈕添加了一個碎片之後,這時按下Back鍵程序就會直接退出。如果這裡我們想模仿類似於返回棧的效果,按下Back鍵可以回到上一個碎片,該如何實現呢?
其實很簡單,FragmentTransaction中提供了一個addToBackStack()方法,可以用於將一個事務添加到返回棧中,修改MainActivity中的代碼,
public class MainActivity extends Activity implements OnClickListener { …… @Override public void onClick(View v) { switch (v.getId()) { case R.id.button: AnotherRightFragment fragment = new AnotherRightFragment(); FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction transaction = fragmentManager. beginTransaction(); transaction.replace(R.id.right_layout, fragment); //加上這句 transaction.addToBackStack(null); transaction.commit(); break; default: break; } } }
transaction.add() 往Activity中添加一個Fragment
transaction.remove() 從Activity中移除一個Fragment,如果被移除的Fragment沒有添加到回退棧,這個Fragment實例將會被銷毀。
transaction.replace() 使用另一個Fragment替換當前的,實際上就是remove()然後add()
transaction.hide() 隱藏當前的Fragment,僅僅是設為不可見,並不會銷毀
transaction.show() 顯示之前隱藏的Fragment
detach() 會將view從UI中移除,和remove()不同,此時fragment的狀態依然由FragmentManager維護。
attach() 重建view視圖,附加到UI上並顯示。
transatcion.commit() 提交一個事務
先上程序運行效果
程序裡用到了RadioGroup作為底部欄 ,selector背景選擇器用於點擊時更換背景,FragmentTransaction切換四個Fragment.
FrameLayout作為載體,顯示四個Fragment
先把幾個重要的文件貼上,這個程序比較復雜,建議下載後學習
頁面下方有源碼">源碼下載
四個Fragment都是類似,這裡給出一個
public class Me_Fragment extends Fragment { @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view =inflater.inflate(R.layout.fragment_me,null); return view; } }
Fragment布局,這裡給出奪寶這個
activity_main.xml
<framelayout android:id="@+id/main_fragment" android:layout_height="0dp" android:layout_weight="1" android:layout_width="match_parent"></framelayout>
底部欄bottom.xml
選擇器selected_ic_home.xml
選擇器的相關知識看我另一篇博文點這裡
MainActivity
package com.peng.fragement_826; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.widget.FrameLayout; import android.widget.RadioButton; import android.widget.RadioGroup; import com.peng.fragement_826.fragment.Discover_Fragment; import com.peng.fragement_826.fragment.Doubao_Fragment; import com.peng.fragement_826.fragment.List_Fragment; import com.peng.fragement_826.fragment.Me_Fragment; public class MainActivity extends AppCompatActivity { private FrameLayout mainFragment; private RadioGroup mainRg; private RadioButton mainDb; private RadioButton mainFx; private RadioButton mainQd; private RadioButton mainMe; //四個fragment頁面 private Doubao_Fragment duobaofragment; private Discover_Fragment discoverFragment; private List_Fragment listFragment; private Me_Fragment meFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mainFragment = (FrameLayout) findViewById(R.id.main_fragment); inintView(); } //頁面底部四個按鈕的點擊 顯示不同的fragment private void inintView() { //底部四個按鈕 奪寶 發現 清單 我的 mainDb = (RadioButton) findViewById(R.id.main_db); mainFx = (RadioButton) findViewById(R.id.main_fx); mainQd = (RadioButton) findViewById(R.id.main_qd); mainMe = (RadioButton) findViewById(R.id.main_me); duobaofragment = new Doubao_Fragment(); getFragmentManager().beginTransaction().replace(R.id.main_fragment, duobaofragment).commit(); //RadioGroup的點擊事件 分別打開不同的fragment mainRg = (RadioGroup) findViewById(R.id.main_rg); mainRg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup radioGroup, int checkedId) { //獲取fragment的管理者 android.app.FragmentManager fragmentManager = getFragmentManager(); //開啟事物 android.app.FragmentTransaction beginTrasaction = fragmentManager.beginTransaction(); switch (checkedId) { case R.id.main_db: if (duobaofragment == null) { duobaofragment = new Doubao_Fragment(); beginTrasaction.add(R.id.main_fragment, duobaofragment); Log.d("peng","--->>>add-one"); } if (discoverFragment != null){ beginTrasaction.hide(discoverFragment); Log.d("peng","--->>>hide-two");} if (listFragment != null){ beginTrasaction.hide(listFragment); Log.d("peng","--->>>hide-three");} if (meFragment != null) { beginTrasaction.hide(meFragment); Log.d("peng","--->>>hide-four"); } beginTrasaction.show(duobaofragment); Log.d("peng","--->>>show-one"); beginTrasaction.commit(); break; case R.id.main_fx: if (discoverFragment == null) { discoverFragment = new Discover_Fragment(); beginTrasaction.add(R.id.main_fragment, discoverFragment); Log.d("peng","--->>>add-two"); } if (duobaofragment != null){ beginTrasaction.hide(duobaofragment); Log.d("peng","--->>>hide-one");} if (listFragment != null){ beginTrasaction.hide(listFragment); Log.d("peng","--->>>hide-three"); } if (meFragment != null){ beginTrasaction.hide(meFragment); Log.d("peng","--->>>hide-four"); } beginTrasaction.show(discoverFragment); Log.d("peng","--->>>show-two"); beginTrasaction.commit(); break; case R.id.main_qd: if (listFragment == null) { listFragment = new List_Fragment(); beginTrasaction.add(R.id.main_fragment, listFragment); } if (duobaofragment != null) beginTrasaction.hide(duobaofragment); if (discoverFragment != null) beginTrasaction.hide(discoverFragment); if (meFragment != null) beginTrasaction.hide(meFragment); beginTrasaction.show(listFragment); beginTrasaction.commit(); break; case R.id.main_me: if (meFragment == null) { meFragment = new Me_Fragment(); beginTrasaction.add(R.id.main_fragment, meFragment); } if (duobaofragment != null) beginTrasaction.hide(duobaofragment); if (listFragment != null) beginTrasaction.hide(listFragment); if (discoverFragment != null) beginTrasaction.hide(discoverFragment); beginTrasaction.show(meFragment); beginTrasaction.commit(); break; default: break; } } }); } }
一個類似於破解的初級實驗。用到的gdb的指令並不多,只是基礎的使用和內存查看的指令。考的大多是匯編代碼的熟練程度和分析能力。不過有幾個函數長的讓人吐血。本著不輕易爆炸的原
使用過百度地圖的同學知道,它有個街景功能,可以看到許多地方的實景。這裡就其街景內容的實現,進行下學習。 在百度地圖SDK的官網上可以看到,百度對開發者提供了很多相關的內容
自己做的一個APP需要用到翻頁閱讀,網上看過立體翻頁效果,不過bug太多了還不兼容。看了一下多看閱讀翻頁是采用平移翻頁的,於是就仿寫了一個平移翻頁的控件。效果如下:在翻頁
在Android開發中,經常需要加載顯示網頁,一般一個頁面在打開後,在等待數據加載的過程中,都需要花一點時間,這個時候往往需要顯示一個轉動的進度條(ProgressBar