반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리

[CookBook] Fragments 이해하기 -3-

2013. 9. 27. 11:15 | Posted by 솔웅


반응형

Adding and Removing Fragments with Device Orientation



fragments를 사용할 때 가장 큰 잇점 중의 하나는 디바이스를 가로 세로 방향으로 돌려서 볼 때 쉽게 fragment를 넣고 뺄 수 있어서 적당한 layout의 view를 사용자에게 보여질 수 있도록 하는 것입니다. 그럼 이렇게 만들기 위해 이전 글에서 다뤘던 소스들을 약간 수정해 보겠습니다. (안드로이드 전화기에서 세웠을 때는 한개의 fragment만 보여지도록요.)


activity_foreground_fragment.xml 에서 두번째 fragment 부분을 주석 처리 합니다.



<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
    <fragment
        android:name="com.androidtablet.foregroundfragmentapp.Fragment1Activity"
        android:id="@+id/fragment1"
        android:layout_weight="1"
        android:layout_width="wrap_content"
        android:layout_height="match_parent" />
 <!--    <fragment
        android:name="com.androidtablet.foregroundfragmentapp.Fragment2Activity"
        android:id="@+id/fragment2"
        android:layout_weight="0"
        android:layout_width="wrap_content"
        android:layout_height="match_parent" /> -->
</LinearLayout>




이렇게 하는 이유는 오직 1개의 fragment만 화면에 표시하기 위해서죠. 이 경우는 안드로이드 전화기가 세워졌을 때 뿐입니다. 눕혀졌을 때나 태블릿 일 경우에는 두개의 fragments들이 좌우로 배치되어야 하겠죠.
그러면 이런 경우를 위해서 어떤 작업을 해야 합니다. 우선 res 폴더 아래에 layout-land 폴더를 생성하세요. 그리고 그 폴더에 activity_foreground_fragment.app 을 복사해 넣으세요.



전화기가 세워졌다가 옆으로 뉘여졌을 때 이 activity는 layout-land 에 있는 layout xml 파일을 사용해서 화면에 표시해 줄 겁니다. 전화기가 다시 세워지면 layout 폴더 안에 있는 xml 을 사용해서 화면을 갱신시킬거구요.



layout_land 폴더에 있는 activity_foreground_fragment.xml 파일에서는 위에 있는 주석을 풀어 주시면 됩니다.



그 다음에는 Fragment1Activity.java 파일을 수정하시면 됩니다.



public class Fragment1Activity extends Fragment {
    OnOptionSelectedListener  myListener;
    boolean large, xlarge;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Context c = getActivity().getApplicationContext();
        View vw = inflater.inflate(R.layout.fragment1, container, false);
        String[] products={"Camera", "Laptop", "Watch",  "Smartphone", "Television"};
        large = ((getResources().getConfiguration().screenLayout  & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE);             
        xlarge =((getResources().getConfiguration().screenLayout  & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE);      
        ListView productsList = (ListView) vw.findViewById(R.id.products_list);
        ArrayAdapter<String> arrayAdpt= new ArrayAdapter<String> (c, R.layout.list_item, products);
        productsList.setAdapter(arrayAdpt);        
        productsList.setOnItemClickListener(new OnItemClickListener(){
            @Override
            public void onItemClick(AdapterView<?> parent, View v, int position, long id){                 
                if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE || large || xlarge){                                      
                    myListener.onOptionSelected(((TextView)  v).getText().toString());  
                 } else {
                    Intent intent = new Intent(getActivity().getApplicationContext(),  DisplayItemActivity.class);
                    intent.putExtra("item", ((TextView) v).getText().toString());
                    startActivity(intent);
                 }

            }
        });
        return vw;
    }
   
    public interface OnOptionSelectedListener {
        public void onOptionSelected(String message);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            myListener = (OnOptionSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + "  must implement OnItemClickListener");
        }
    }   
}



위의 굵은 글씨체가 추가된 부분입니다. 리스트뷰의 아이템이 클릭 됐을 때 onItemClick() 메소드를 보면  우선 device가 landscape 이거나 large 혹은 xlarge 즉 태블릿인 경우를 체크합니다. 만약에 그렇다면 fragment2를 보여줍니다. 즉 그럴 경우 onOptionSelected() 메소드가 호출되고 이때 선택된 아이템의 이름이 파라미터로 전달 되는 겁니다. 그러면 Fragment2에서 이 파라미터를 받아서 화면에 출력하겠죠.



위 경우가 아니라면 즉 디바이스가 전화기이고 세워진 상태라면 (Portrait orientation) fragment2는 호출 되지 않을 겁니다. 리스트뷰에 있는 아이템이 선택 됐으면 그 이름이 다른 화면에 표시 되어야 합니다. 다른 화면에 표시된다는 얘기는 다른 activity가 필요하다는 얘기입니다. 그리고 다른 activity로 옮길 경우에는 Intent를 사용해야 되구요. 이 경우 현재의 Context를 같이 보내 주어야 합니다. getActivity().getApplicationContext(). 그리고 불려질 Activity를 정해주고 (DisplayItemActivity.class) 그리고 추가적으로 데이터를 넣어서 이것을 전달합니다. 마지막으로 startActivity() 를 하면 다음 화면이 불려 오겠죠.



그러면 이제 할 일을 DisplayItemActivity.java 를 만들어야 겠네요.
소스 코드는 아래와 같습니다.



public class DisplayItemActivity extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
            finish();
            return;
        }
        setContentView(R.layout.fragment2);
        Bundle extras = getIntent().getExtras();
        if (extras != null) {
            String selectedItem = extras.getString("item");
            TextView selectedOpt = (TextView) findViewById(R.id.selectedopt);
            selectedOpt.setText("You have selected "+selectedItem);
        }
    }
}



onCreate() 만 있죠? 맨 처음에 이 기계가 Landscape 모드이면 그냥 끝내고 return 을 해 버립니다. 그리고 난 후 fragment2.xml 을 view로 세팅하죠.
그리고 나서 이전 파일에서 전달해 준 데이터를 체크합니다. getExtra()가 그 일을 합니다. 그리고 item이란 key 값을 이용해서 그 value 값을 selectedItem에 담구요. 그 값을 텍스트뷰에 넣어 줍니다.


이렇게 하면 완성된 겁니다.
그런데 한가지 더 해야 될 게 있는데요.
DisplayItemActivity 라는 Activity가 새로 생겼으면 이것을 AndroidManifest.xml 에 신고를 해야 합니다.
<activity android:name=".DisplayItemActivity" android:label="@string/app_name" /> 을 추가해야 하는데요.
혹시 Manifest 파일에 액티비티 추가하는 방법을 모르시면 관련 글을 보시고 참고하시기 바랍니다.



그리고 한가지 더 해야 할 일이 있는데요.
현재 layout과 layout-land 폴더에만 xml layout 파일이 있습니다. 이건 전화기에만 해당되는데요. 태블릿에도 적용시키기 위해서 두개의 폴더를 더 만듭니다. layout-sw600dp 와 layout-sw720dp 폴더를요. 그리고 이 앱에서는 전화기의 landscape 인 경우와 7인치 10인치 태블릿의 landscape, portrait orientation 모두 그 구성이 같습니다. 그러니까 lauout-land 에 있는 activity_foreground_fragment_app.xml 파일을 복사해서 위 두 폴더 밑에 넣습니다.



이제 이 앱을 돌리면 안드로이드 전화기인 경우에는 Portrait orientation인 경우 첫화면에는 리스트뷰만 표시되고 그 리스트 뷰의 아이템을 클릭했을 때 그 이름이 두번째 화면에서 표시되게 됩니다. landscape orientation으로 바뀌게 되면 태블릿과 마찬가지로 두개의 fragment들이 좌우로 배치되고 좌측의 리스트뷰 아이템을 클릭하면 그 이름이 우측의 텍스트 뷰에 출력되게 됩니다.

반응형