且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Fragment详解(三)--->横竖屏幕切换完整示例

更新时间:2022-08-26 13:53:07

MainActivity如下:

package cc.testsimplefragment2;

import android.app.Activity;
import android.os.Bundle;
/**
 * Demo描述:
 * Fragment使用示例
 * 
 * 备注说明:
 * 1 在main.xml中存在一个Fragment即
 *   TitleListFragment.用它来显示Titles
 * 2 点击TitleListFragment中的某个条目的时候
 *   判断的横竖屏
 *   2.1 若是横屏,则用另外一个Fragment显示详细信息
 *   2.2 若是竖屏,则启动另一个Activity显示详细信息
 *       2.2.1 在该Activity中动态添加一个Fragment显示详细信息
 * 
 * 参考文档:
 * 1 http://blog.csdn.net/t12x3456/article/details/8120309
 * 2 http://blog.csdn.net/nkmnkm/article/category/958669/5
 * 3 http://blog.csdn.net/xiaanming/article/details/9254749
 *   Thank you very much
 *
 */
public class MainActivity extends Activity {
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main); 
	}
	
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		System.out.println("---> MainActivity onSaveInstanceState()");
	}

}


TitleListFragment如下:

package cc.testsimplefragment2;

import android.app.FragmentTransaction;
import android.app.ListFragment;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class TitleListFragment extends ListFragment {
	//当前是否为横屏
	private boolean currentIsLand;
	//当前选中位置
	private int currentCheckedPosition = -1; 
	private final String currentCheckedKey="currentChecked";
	
	//每次重绘Fragment时都会调用该onActivityCreated()方法
	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
        System.out.println("---> onActivityCreated");
		//设置适配器
		ArrayAdapter<String> arrayAdapter=
		new ArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_checked, Data.TITLES);
		setListAdapter(arrayAdapter); 

		//判断当前是否为横屏
		//注意方式:
		//先利用getActivity()找到该Fragment隶属于的Activity,再findViewById()
		//为什么要这么判断是否是横屏呢?
		//因为横屏的时候会去读取layout-land下的main.xml布局文件
		//在该布局文件下有一个RelativeLayout,其id为containerRelativeLayout
		//所以,若能找到它那么就可以表明当前是横屏
		View containerView = getActivity().findViewById(R.id.containerRelativeLayout);
		currentIsLand = containerView != null && containerView.getVisibility() == View.VISIBLE; 

		if (savedInstanceState != null) {
			currentCheckedPosition = savedInstanceState.getInt(currentCheckedKey, 0);
			getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); 
			getListView().setItemChecked(currentCheckedPosition, true); 
			System.out.println("---> onActivityCreated() currentCheckedPosition="+currentCheckedPosition);
		}else{
			System.out.println("---> onActivityCreated() savedInstanceState == null ");
		}

		if (currentIsLand) { 
			//设置ListView为单选模式
			getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); 
			showDetailContent(currentCheckedPosition); 
		}
	}
	
	@Override
	public void onStart() {
		super.onStart();
		System.out.println("---> onStart");
	}
	
	//处理手机一直在竖屏时:
	//点击标题,跳转后,再按下back键的情况
	@Override
	public void onResume() {
		super.onResume();
		System.out.println("---> onResume");
		if (!currentIsLand) {
			getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
			//currentCheckedPosition默认为-1
			//所以在第一次时不选择任何一个
			if (currentCheckedPosition>=0) {
				getListView().setItemChecked(currentCheckedPosition, true);
			}
		}
	}

	//保存数据
	//Fragment被系统或者某些内存清理,或者横竖屏切换而被销毁时
	//将会触发onSaveInstanceState(Bundle savedInstanceState):
	//Called to ask the fragment to save its current dynamic state,
	//so it can later be reconstructed in a new instance of its process is restarted.
	//然后调用onActivityCreated()生命周期方法,重绘Fragment
    
	//存在的疑问:
	//在手机一直竖屏的情况下,点击TitleListFragment的条目
	//为什么会执行该onSaveInstanceState()方法和MainActivity的
	//onSaveInstanceState()方法
	@Override
	public void onSaveInstanceState(Bundle bundle) {
		super.onSaveInstanceState(bundle);
		bundle.putInt(currentCheckedKey, currentCheckedPosition);
		System.out.println("---> onSaveInstanceState()");
		System.out.println("---> onSaveInstanceState() currentCheckedPosition="+currentCheckedPosition);
	}

	
	//点击ListFragment上的某个条目时调用
	@Override
	public void onListItemClick(ListView l, View v, int position, long id) {
		showDetailContent(position); 
	}

	//显示详细内容
	private void showDetailContent(int index) {
		//保存当前被选中的位置
		currentCheckedPosition=index;
		//横屏时
		if (currentIsLand) {
			//1  先设置TitleListFragment
			//  改变ListFragment的index位置被选中
			getListView().setItemChecked(index, true); 

			//2  再设置DetailFragment
			//  利用FragmentManager判断在某个容器(container)中是否有一个DetailFragment
			//  如果没有或在有的情况下其CheckedIndex不等于当前被选中的index
			//  则进行replace()操作
			DetailFragment detailFragment = 
			(DetailFragment) getFragmentManager().findFragmentById(R.id.containerRelativeLayout); 
			if (detailFragment == null || detailFragment.getCheckedIndex() != index) {
				//生成新的Fragment.
				detailFragment = DetailFragment.newInstance(index);
				//开始Fragment的事务Transaction
				//因为在这个事务中执行了replace()操作,所以会将该
				//detailFragment attach到activity,按照生命周期
				//的顺序必然会调用DetailFragment的onCreateView().
				//更加白话地说:其实相当于我们先做了一些内在的东西,再做了外在的东西.
				//什么意思呢?
				//内在的部分:我们先new了一个DetailFragment,并且为这个DetailFragment
				//设置了一些参数.
				//这些都体现在了DetailFragment.newInstance(index)方法中
				//外在的部分:利用replace()将该DetailFragment attach到activity
				//这些都体现在了DetailFragment的onCreateView()方法中.所以在
				//该方法中我们可以去取为此DetailFragment设置的参数.
				//即方法getCheckedIndex()
				FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
				//替换容器(container)原来的Fragment
				fragmentTransaction.replace(R.id.containerRelativeLayout, detailFragment); 
				//设置转换效果
				fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); 
				//提交事务
				fragmentTransaction.commit(); 
			}
        //竖屏时
		} else { 
			Intent intent = new Intent(getActivity(),DetailActivity.class);
			intent.putExtra("index", index); 
			startActivity(intent); 
		}
	}

}


DetailFragment如下:

package cc.testsimplefragment2;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ScrollView;
import android.widget.TextView;

public class DetailFragment extends Fragment {

	//往ScrollView中添加一个TextView然后将其返回
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
		if (container == null) {
			return null;
		}
		ScrollView scrollView = new ScrollView(getActivity()); 
		TextView textView = new TextView(getActivity()); 
		textView.setPadding(10, 10, 10, 10); 
		scrollView.addView(textView); 
		textView.setText(Data.DETAILS[getCheckedIndex()]); 
		return scrollView;
	}
	
	//生成DetailFragment实例,并且保存index
	public static DetailFragment newInstance(int index) {
		DetailFragment detailFragment = new DetailFragment();
		Bundle bundle = new Bundle(); 
		bundle.putInt("index", index); 
		detailFragment.setArguments(bundle);
		return detailFragment;
	}

	//取出index
	public int getCheckedIndex() {
		int index =getArguments().getInt("index", 0);
		return  index;
	}
}


DetailActivity如下:

package cc.testsimplefragment2;
import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
/**
 * 在此Activity中我们将一个Fragment嵌入到
 * 该Activity中进行显示
 */
public class DetailActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//横屏的处理
		if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
			finish();
			return;
		}
        
		//竖屏的处理
		//此处的道理和TitleListFragment中对于横屏的
		//处理很相似,只是方式稍有差别.
		//1 生成设置好参数的DetailFragment
		//2 将此DetailFragment attach到当前的activity
		if (savedInstanceState == null) { 
			DetailFragment detailFragment = new DetailFragment();
			detailFragment.setArguments(getIntent().getExtras()); 
			getFragmentManager()
			.beginTransaction()
			.add(android.R.id.content, detailFragment)
			.commit(); 
		}
	}
}


Data如下:

package cc.testsimplefragment2;
public final class Data {
	//标题
    public static final String[] TITLES = { "标题1","标题2", "标题3","标题4"};
    //内容
    public static final String[] DETAILS = { "内容1","内容2", "内容3","内容4"};
}


layout/main.xml如下:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="horizontal" 
	android:layout_width="match_parent"
	android:layout_height="match_parent">

	<fragment 
		android:id="@+id/titles"
		class="cc.testsimplefragment2.TitleListFragment"
		android:layout_weight="1" 
		android:layout_width="0px"
		android:layout_height="match_parent" />

</LinearLayout>

 

layout-land/main.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<!-- 横屏时的布局文件 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="horizontal" 
	android:layout_width="match_parent"
	android:layout_height="match_parent">

	<fragment 
		android:id="@+id/titles"
		class="cc.testsimplefragment2.TitleListFragment" 
		android:layout_weight="1" 
		android:layout_width="0px"
		android:layout_height="match_parent" 
     />

	<RelativeLayout 
	    android:id="@+id/containerRelativeLayout"
		android:layout_weight="2" 
		android:layout_width="0px"
		android:layout_height="match_parent" 
		android:background="?android:attr/detailsElementBackground"
	 />

</LinearLayout>


AndroidManifest.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cc.testsimplefragment2"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="15" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:label="@string/app_name"
            android:name="cc.testsimplefragment2.MainActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
	   <activity 
	       android:name="cc.testsimplefragment2.DetailActivity"
	       android:label="详细内容的Activity" 
       />
	
    </application>

</manifest>