XSuperMES移動端運用FragmentActivity適配大屏幕android
XSuperMES移動端運行在各類各樣的設備中,有小屏幕的手機,超大屏的平板甚至電視。針對屏幕尺寸的差距,不少狀況下,都是先針對手機開發一套app,而後拷貝一份,修改佈局以適應什麼超級大屏的。難道沒法作到一個app能夠同時適應手機和平板嗎?答案是,固然有,那就是Fragment.Fragment出現的初衷就是爲了解決這樣的問題。數據庫
你能夠把Fragment當成Activity一個界面的一部分,甚至Activity的界面由徹底不一樣的Fragment組成,更帥氣的是Fragment有本身的聲明週期和接收、處理用戶的事件,這樣就沒必要要在一個Activity裏面寫一堆事件、控件的代碼了。更爲重要的是,你能夠動態的添加、替換、移除某個Fragment。cookie
一、如何使用fragment activityapp
要想用Fragment 功能必須先讓activity繼承FragmentActivity,其緣由是裏面包含了Fragment運做的FragmentManager接口的實現類 FragmentManagerImpl ,由這個類管理全部Fragment的顯示、隱藏ide
1.使用最簡單的Fragment,咱們只要繼承Fragment就能夠函數
public class TextFragment extends Fragment{ 佈局
private String mMsg; this
public void setMessage(String message){ xml
this.mMsg = message; 繼承
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
final Context context = getActivity();
FrameLayout root = new FrameLayout(context);
root.setBackgroundColor(Color.YELLOW);
TextView tv = new TextView(context);
tv.setText(mMsg);
tv.setGravity(Gravity.CENTER);
root.addView(tv, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
return root;
}
}
首先Fragment 就能夠把它看成一個view , 只不過這個view 與 activity同樣有了生命週期函數
Fragment.onCreateView() 函數就是用於生成這個Fragment佈局的view的,相似baseadapter.getView()
這樣一個包含一個TextView的簡單佈局就完成了。
2.重寫咱們本身的FragmentActivity.
這裏面主要要經過FragmentManager 來進行Fragment的添加和刪除:
public class TextFragment extends Fragment{
private String mMsg;
public void setMessage(String message){
this.mMsg = message;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
final Context context = getActivity();
FrameLayout root = new FrameLayout(context);
root.setBackgroundColor(Color.YELLOW);
TextView tv = new TextView(context);
tv.setText(mMsg);
tv.setGravity(Gravity.CENTER);
root.addView(tv, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
return root;
}
}
首先Fragment 就能夠把它看成一個view , 只不過這個view 與 activity同樣有了生命週期函數
public class DoorFragmentActivity extends FragmentActivity{
public static final String FRAG_SMS = "sms_list_frag";
public static final String FRAG_TEXT = "text_frag";
private Fragment mSMSFragment;
private Fragment mTextFragment;
private FragmentManager mFragMgr;
private Button mMenuBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.door_fragment_activity_layout);
mFragMgr = getSupportFragmentManager();
mMenuBtn = (Button) findViewById(R.id.door_menu_btn);
mMenuBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
showFragments(FRAG_TEXT, true);
}
});
mMenuBtn.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
// TODO Auto-generated method stub
return false;
}
});
initFragments();
showFragments(FRAG_SMS, false);
}
private void initFragments(){
mSMSFragment = new SMSListFragment();
TextFragment textfrag = new TextFragment();
textfrag.setMessage("這是 菜單界面");
mTextFragment = textfrag;
}
private void showFragments(String tag, boolean needback){
FragmentTransaction trans = mFragMgr.beginTransaction();
if(needback){
trans.setCustomAnimations(R.anim.frag_enter,
R.anim.frag_exit);
trans.add(R.id.door_root_content_fl, getFragmentByTag(tag), tag);
trans.addToBackStack(tag);
}else{
trans.replace(R.id.door_contents_fl, getFragmentByTag(tag), tag);
}
trans.commit();
}
private Fragment getFragmentByTag(String tag){
if(FRAG_SMS.equals(tag)){
return mSMSFragment;
}
if(FRAG_TEXT.equals(tag)){
return mTextFragment;
}
return null;
}
}
咱們主要經過 FragmentTransation的一些方法來處理Fragment的:
1) trans.add(fragment, tag); 這個實際是 containerViewId = 0 調用的3)
2) trans.add(containerViewId, fragment); 這個實際是 tag = null 調用的 3)
3) trans.add(containerViewId, fragment, tag); 若是containerViewId != 0實際上調用的是獲取到
fragment的 onCreateView方法返回的view 並加入到containerViewId這個viewgroup中去即 viewgroup.addView(fragment.onCreateView());
未解決問題:containerViewId = 0 的時候表明什麼??
4) trans.replace(containerViewId, fragment) 同樣是null tag調用 5)
5) trans.replace(containerViewId, fragment, tag) 這個同樣是添加一個fragment到對應的container中去,只不過比add多了一步對相同containerViewId中已有的fragment檢索,進行removeFragment操做,再去添加這個新來的fragment
6) trans.addToBackStack(tag); 若是你的fragment對於back鍵有相似activity的回退響應,就要記得把它加入到裏面去,trans裏面模擬了棧,可是個人回退沒有響應我設置的exit anim 這個無語還沒解決
3.再使用下ListFragment,我這裏寫的是SMSListFragment繼承了ListFragment:
public class SMSListFragment extends ListFragment{
private ConversationListAdapter mAdapter;
private ConversationQuery mQuery;
private long startTime;
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
mAdapter = new ConversationListAdapter(getActivity());
mQuery = new ConversationQuery(getActivity().getContentResolver());
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
setListAdapter(mAdapter);
}
@Override
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
startAsyncQuery();
}
@Override
public void onStop() {
// TODO Auto-generated method stub
super.onStop();
mAdapter.getCursor().close();
mAdapter.changeCursor(null);
}
public void startAsyncQuery() {
startTime = System.currentTimeMillis();
mQuery.startQuery(1, null, Conversation.sAllThreadsUri,
Conversation.ALL_THREADS_PROJECTION, null, null,
Conversation.CONVERSATION_ORDER);
}
private final class ConversationQuery extends AsyncQueryHandler {
public ConversationQuery(ContentResolver cr) {
super(cr);
// TODO Auto-generated constructor stub
}
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
// TODO Auto-generated method stub
System.out.println("conversation cursor size : "
+ cursor.getCount());
mAdapter.changeCursor(cursor);
Toast.makeText( getActivity(),
"查詢短信會話個數:" + cursor.getCount() + ",花費"
+ (System.currentTimeMillis() - startTime) + " ms",
Toast.LENGTH_LONG).show();
}
}
}
代碼中能夠知道和使用普通的ListActivity徹底沒區別,
onCreate()中完成本身要一次性初始的東西,我在裏面主要是初始化一個adapter和一個對sms數據庫的查詢
在onActivityCreated()中將adapter設置給listview,這個不肯定有沒有更好的位置,
而後進入咱們熟悉的生命週期方法:
onStart()中,開啓查詢
onStop()中,咱們界面已經不在顯示了,因此咱們不關心數據庫變化了,close cursor
4.主頁面的佈局文件:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/door_root_content_fl"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:id="@+id/door_contents_fl"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="55dp"
android:orientation="horizontal" >
<Button
android:id="@+id/door_menu_btn"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="菜單" />
</LinearLayout>
</LinearLayout>
</FrameLayout>