프로그래밍 방식으로 작성된 컨텐츠 뷰를 사용하여 활동에 프래그먼트를 추가하는 방법


240

프로그래밍 방식으로 레이아웃을 구현하는 활동에 Fragment를 추가하고 싶습니다. Fragment 문서를 살펴 보았지만 필요한 것을 설명하는 예제는 많지 않습니다. 내가 작성하려고 한 코드 유형은 다음과 같습니다.

public class DebugExampleTwo extends Activity {

    private ExampleTwoFragment mFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FrameLayout frame = new FrameLayout(this);
        if (savedInstanceState == null) {
            mFragment = new ExampleTwoFragment();
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.add(frame.getId(), mFragment).commit();
        }

        setContentView(frame);
    }
}

...

public class ExampleTwoFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, 
                             ViewGroup container, 
                             Bundle savedInstanceState) {
        Button button = new Button(getActivity());
        button.setText("Hello There");
        return button;
    }
}

이 코드는 컴파일되지만 시작시 충돌합니다. 아마도 내 FragmentTransaction.add()것이 올바르지 않기 때문일 것 입니다. 이를 수행하는 올바른 방법은 무엇입니까?

답변:


198

해당 코드에 하나 이상의 문제가 있음이 밝혀졌습니다. 액티비티와 동일한 Java 파일 내에서 공개 내부 클래스가 아닌 프래그먼트를 그렇게 선언 할 수 없습니다. 프레임 워크는 조각의 생성자 (매개 변수 없음)가 공개되고 표시 될 것으로 예상합니다. 프래그먼트를 내부 클래스로 Activity로 이동하거나 프래그먼트에 대한 새 Java 파일을 작성하면 문제가 해결됩니다.

두 번째 문제는이 방법으로 프래그먼트를 추가 할 때 프래그먼트의 포함 뷰에 대한 참조를 전달해야하며 해당 뷰에 사용자 정의 ID가 있어야한다는 것입니다. 기본 ID를 사용하면 앱이 중단됩니다. 업데이트 된 코드는 다음과 같습니다.

public class DebugExampleTwo extends Activity {

    private static final int CONTENT_VIEW_ID = 10101010;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FrameLayout frame = new FrameLayout(this);
        frame.setId(CONTENT_VIEW_ID);
        setContentView(frame, new LayoutParams(
            LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

        if (savedInstanceState == null) {
            Fragment newFragment = new DebugExampleTwoFragment();
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.add(CONTENT_VIEW_ID, newFragment).commit();
        }
    }

    public static class DebugExampleTwoFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            EditText v = new EditText(getActivity());
            v.setText("Hello Fragment!");
            return v;
        }
    }
}

115
활동의 최상위 컨텐츠보기로 프래그먼트 만 사용하려는 경우을 사용할 수 있습니다 ft.add(android.R.id.content, newFragment). 프래그먼트 컨테이너가 액티비티의 컨텐츠 뷰가 아닌 경우 사용자 정의 레이아웃을 생성하고 ID를 설정하면됩니다.
Tony Wong

25
ID를 하드 코딩하는 대신 XML로 정의하고 일반 (R.id.myid)으로 참조 할 수 있습니다 .
Jason Hanley

1
나는 그것을하는 방법을 모른다. 그러나 ID는 당신이 그것을 사용해야하는 범위에서 유일해야한다는 것을 기억하십시오.
Jason Hanley

2
ID는 포함하는 레이아웃의 현재 계층 내에서 해당 레벨에서 고유해야합니다. 따라서 선형 레이아웃으로 싸여 있다고하면 해당 선형 레이아웃 내의 다른보기 중 unqiue 만 있으면됩니다.
Shaun

1
setId (View.NO_ID)를 사용하여 동적으로 ID를 작성한 다음 getId ()를 사용하여 ID를 확인할 수 있습니다.
enl8enmentnow

71

Tony Wong의 의견을 읽은 후에 생각해 낸 내용은 다음과 같습니다 .

public class DebugExampleTwo extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addFragment(android.R.id.content,
                    new DebugExampleTwoFragment(),
                    DebugExampleTwoFragment.FRAGMENT_TAG);
    }

}

...

public abstract class BaseActivity extends Activity {

    protected void addFragment(@IdRes int containerViewId,
                               @NonNull Fragment fragment,
                               @NonNull String fragmentTag) {
        getSupportFragmentManager()
                .beginTransaction()
                .add(containerViewId, fragment, fragmentTag)
                .disallowAddToBackStack()
                .commit();
    }

    protected void replaceFragment(@IdRes int containerViewId,
                                   @NonNull Fragment fragment,
                                   @NonNull String fragmentTag,
                                   @Nullable String backStackStateName) {
        getSupportFragmentManager()
                .beginTransaction()
                .replace(containerViewId, fragment, fragmentTag)
                .addToBackStack(backStackStateName)
                .commit();
    }

}

...

public class DebugExampleTwoFragment extends Fragment {

    public static final String FRAGMENT_TAG = 
        BuildConfig.APPLICATION_ID + ".DEBUG_EXAMPLE_TWO_FRAGMENT_TAG";

    // ...

}

코 틀린

Kotlin을 사용하는 경우 Google 의 Kotlin 확장 프로그램 이 제공하는 기능을 보거나 직접 작성하십시오.


그렇게하지 마십시오! if (savedInstanceState == null)조각을 만들기 전에 확인 하거나 화면을 회전 한 후에 두 조각 또는 조각이 다시 정렬됩니다. add방법을 전혀 사용하지 마십시오 ! 만 replace. 아니면 이상한 행동을하게 될 것입니다.
CoolMind

"backStackStateName"의 값은 어디에서 얻습니까? (바꾸기 기능을 사용하는 경우)
vikzilla

@vikzilla 여기문서 에서 꽤 좋은 답변을 찾을 수 있습니다 . 간단히 말해서, backStackStateName문자열은 사용자가 정의한 것입니다.
JJD

34
    public class Example1 extends FragmentActivity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
          DemoFragment fragmentDemo = (DemoFragment) 
          getSupportFragmentManager().findFragmentById(R.id.frame_container);
          //above part is to determine which fragment is in your frame_container
          setFragment(fragmentDemo);
                       (OR)
          setFragment(new TestFragment1());
        }

        // This could be moved into an abstract BaseActivity 
        // class for being re-used by several instances
        protected void setFragment(Fragment fragment) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = 
                fragmentManager.beginTransaction();
            fragmentTransaction.replace(android.R.id.content, fragment);
            fragmentTransaction.commit();
        }
    }

활동 또는 FramentActivity에 단편을 추가하려면 컨테이너가 필요합니다. 해당 컨테이너는 " Framelayout" 이어야하며 이는 XML에 포함될 수 있거나 그렇지 않으면 " android.R.id.content" 와 같은 기본 컨테이너를 사용하여 활동에서 단편을 제거하거나 바꿀 수 있습니다.

main.xml

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
 <!-- Framelayout to display Fragments -->
   <FrameLayout
        android:id="@+id/frame_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <ImageView
        android:id="@+id/imagenext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_margin="16dp"
        android:src="@drawable/next" />
</RelativeLayout>

29

모든 답변을 읽은 후 나는 우아한 방법을 생각해 냈습니다.

public class MyActivity extends ActionBarActivity {

 Fragment fragment ;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    FragmentManager fm = getSupportFragmentManager();
    fragment = fm.findFragmentByTag("myFragmentTag");
    if (fragment == null) {
        FragmentTransaction ft = fm.beginTransaction();
        fragment =new MyFragment();
        ft.add(android.R.id.content,fragment,"myFragmentTag");
        ft.commit();
    }

}

기본적으로 프래그먼트의 컨테이너로 frameLayout을 추가 할 필요가 없습니다 대신 안드로이드 루트 뷰 컨테이너에 프래그먼트를 똑바로 추가 할 수 있습니다

중요 : onrecreation 프로세스 중에 프래그먼트 변수 인스턴스 상태를 잃어 버리지 않는 한 여기에 표시된 대부분의 접근 방식으로 replace 프래그먼트사용 하지 마십시오 .


답변 주셔서 감사합니다, 이것은 전체 화면에 조각 탭을 추가합니까? 그러나 한 프레임 레이아웃 또는 뷰 호출기에 추가하는 방법은 무엇입니까?
flankechen

6
public abstract class SingleFragmentActivity extends Activity {

    public static final String FRAGMENT_TAG = "single";
    private Fragment fragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
        if (savedInstanceState == null) {
            fragment = onCreateFragment();
           getFragmentManager().beginTransaction()
                   .add(android.R.id.content, fragment, FRAGMENT_TAG)
                   .commit();
       } else {
           fragment = getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
       }
   }

   public abstract Fragment onCreateFragment();

   public Fragment getFragment() {
       return fragment;
   }

}

사용하다

public class ViewCatalogItemActivity extends SingleFragmentActivity {
    @Override
    public Fragment onCreateFragment() {
        return new FragmentWorkShops();
    }

}

6

대한 API 레벨 17 이상, View.generateViewId()이 문제를 해결합니다. 유틸리티 메소드는 빌드 시간에 사용되지 않는 고유 ID를 제공합니다.


3
스택 오버플로에 오신 것을 환영합니다! 이 이론적으로 질문에 대답 할 수 있습니다 동안, 바람직 할 것이다 여기에 대한 대답의 본질적인 부분을 포함하고 참조 할 수 있도록 링크를 제공합니다.
SuperBiasedMan

3

Kotlin에서 프로그래밍 방식으로 활동에 단편을 첨부하려면 다음 코드를 볼 수 있습니다.

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

            // create fragment instance
            val fragment : FragmentName = FragmentName.newInstance()

            // for passing data to fragment
            val bundle = Bundle()
            bundle.putString("data_to_be_passed", DATA)
            fragment.arguments = bundle

            // check is important to prevent activity from attaching the fragment if already its attached
            if (savedInstanceState == null) {
                supportFragmentManager
                    .beginTransaction()
                    .add(R.id.fragment_container, fragment, "fragment_name")
                    .commit()
            }
        }

    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.MainActivity">

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

FragmentName.kt

class FragmentName : Fragment() {

    companion object {
        fun newInstance() = FragmentName()
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

        // receiving the data passed from activity here
        val data = arguments!!.getString("data_to_be_passed")
        return view
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
    }

}

Kotlin의 Extensions 에 익숙하다면 기사를 따르면 이 코드를 더 잘 활용할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.