달달한 스토리

728x90
반응형

일단 제목이 어렵다.

 

이게 무슨 소리인가 할 수도 있겠다.

 

해답을 겨우 찾을 수 있어서 다행이었다.

 

아무리 찾아도 스택오버플로우에도 가도 알 길이 없던 중에,

 

콜백 리스너!라는 방법을 알게 되었고,

 

바로 사용을 해보았다.

 

우선 나는 자바에 대한 지식이 깊지도 않고,

 

안드로이드에 대해 아직 공부한 지 3달이 조금 넘은

 

새내기라 정확하지 않을 수도 있다는 점을 명시한다.

 

우선 상황은 이러했다.

 

스택오버플로우에 올리기 위해서 영어로 썼던 것이다.

 

우선 상황은 이러했다.

 

프래그먼트에서 뷰 페이저를 두고 그 위에 여러 가지 프래그먼트가 있는데,

 

다이얼로그에서 버튼을 클릭하면,

 

저 뷰 페이저에 프래그먼트로 내용이 전달되는 액션을 취하려고 했다.

 

다이얼로그에서 프래그먼트로 전달하고, 프래그먼트로 전달도 해보고,

 

어뎁터를 통해 전달도 해보고,

 

별짓을 다해보았지만,

 

(번들도 해보았지만, 계속 null값...)

 

데이터가 전달도 안되고,

 

받아지지도 않고, 며칠 동안 골머리를 앓았다.

 

그러다가 콜백 메서드를 보았는데,

 

방법은 이러하다.

 


해결법

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Bottom_Fragment_1 bottom_fragment_1 = new Bottom_Fragment_1();

        getSupportFragmentManager().beginTransaction().replace(R.id.container,bottom_fragment_1).commitAllowingStateLoss();
        //프래그먼트 트랜잭션 해주기
    }
}

우선 가볍게 메인 액티비티를 만들고, 그 위에 프래그먼트를 띄워주기 위해

 

트랜젝션을 하겠다.

 

그다음에 xml을 작성한다.

 

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
    android:id="@+id/container"
    tools:context=".MainActivity">

</FrameLayout>

프래그먼트를 띄우기 위해 프레임 레이아웃으로 바꾸어 주고,

 

id를 container로 지정해준다.

 

 

Bottom_Fragment_1

public class Bottom_Fragment_1 extends Fragment {
    ViewGroup viewGroup;
    public static Button dialog_btn; //다이얼로그 띄우는 버튼, Frag1에서 참조를 위해 static으로 해둔다.

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        viewGroup = (ViewGroup) inflater.inflate(R.layout.activity_bottom__fragment_1, container, false); //인플레이션 해준다.

        dialog_btn = viewGroup.findViewById(R.id.button3); //참조는 이 곳에서

        imViewPager(); //뷰페이저 2 생성

        return viewGroup;
    }

    private void imViewPager() {

        /* setup infinity scroll viewpager */
        ViewPager2 viewPageSetUp = viewGroup.findViewById(R.id.SetupFrg_ViewPage_Info); //여기서 뷰페이저를 참조한다.
        FragPagerAdapter SetupPagerAdapter = new FragPagerAdapter(getActivity());
        viewPageSetUp.setAdapter(SetupPagerAdapter);
        viewPageSetUp.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);
        viewPageSetUp.setOffscreenPageLimit(5);
        // 무제한 스크롤 처럼 보이기 위해서는 0페이지 부터가 아니라 1000페이지 부터 시작해서 좌측으로 이동할 경우 999페이지로 이동하여 무제한 처럼 스크롤 되는 것 처럼 표현하기 위함.
        viewPageSetUp.setCurrentItem(2);

        final float pageMargin = (float) getResources().getDimensionPixelOffset(R.dimen.pageMargin); //페이지끼리 간격
        final float pageOffset = (float) getResources().getDimensionPixelOffset(R.dimen.offset); //페이지 보이는 정도

        viewPageSetUp.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            @Override
            public void onPageSelected(int position) {
                super.onPageSelected(position);

            }
        });
        viewPageSetUp.setPageTransformer(new ViewPager2.PageTransformer() {
            @Override
            public void transformPage(@NonNull View page, float position) {
                float offset = position * - (2 * pageOffset + pageMargin);
                if(-1 > position) {
                    page.setTranslationX(-offset);
                } else if(1 >= position) {
                    float scaleFactor = Math.max(0.7f, 1 - Math.abs(position - 0.14285715f));
                    page.setTranslationX(offset);
                    page.setScaleY(scaleFactor);
                    page.setAlpha(scaleFactor);
                } else {
                    page.setAlpha(0f);
                    page.setTranslationX(offset);
                }
            }
        });

    }

}

 

여기선 조금 복잡할 수도 있다.

 

아래 imViewPager 메서드는 저번 편에서 썼던 뷰 페이저 2를 그대로 사용하였다.

 

그것 빼고는 어려운 점은 없을 것이다.

 

여기서 중요한 것은 

 

public static Button dialog_btn;이다.

 

static을 주면서

 

다른 액티비티나 프래그먼트에서 이 버튼을 참조할 수 있게 만든 것이다.

 

activity_bottom__fragment_1

<?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=".Bottom_Fragment_1">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="난 제일 밑바닥 프래그먼트야"
        android:textSize="30sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.331" />

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/SetupFrg_ViewPage_Info"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_marginTop="232dp"
        android:layout_marginBottom="130dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        app:layout_constraintVertical_bias="0.0" >

    </androidx.viewpager2.widget.ViewPager2>

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="다이어로그 띄우기"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.481" />
</androidx.constraintlayout.widget.ConstraintLayout>

그러고 나서 이 프래그먼트의 xml을 만든다.

 

다이얼로그 버튼을 하나 만들고,

 

아래의 뷰 페이저의 프래그먼트가 들어갈 자리를 만든다.

 

우선 뷰 페이저 프래그먼트부터 만들어 보겠다.

 

 

FragPagerAdapter

public class FragPagerAdapter extends FragmentStateAdapter {
    // Real Fragment Total Count
    private final int mSetItemCount = 1; //화면에 출력될 프래그먼트 개수4


    public FragPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
        super(fragmentActivity);
    }


    @NonNull
    @Override
    public Fragment createFragment(int position) { //프래그먼트 순서에 맞게 넣어주세요.
        int iViewIdx = getRealPosition(position);
        switch( iViewIdx ) {
            case 0    : { return new Frag1(); }
//            case 1    : { return new Frag2(); }
//            case 2    : { return new Frag3(); }
//            case 3    : { return new Frag4(); }
//            case 4    : { return new Frag5(); }
//            case 5    : { return new Frag6(); }
            default   : { return new Frag1(); } //기본으로 나와있는 프래그먼트
        }
    }

    public int getRealPosition(int _iPosition){
        return _iPosition % mSetItemCount;
    }

    @Override
    public long getItemId(int position) {
        return super.getItemId(position);
    }

    @Override
    public int getItemCount() {
        return Integer.MAX_VALUE;
    }
}

 

우선 어뎁터이다. 저번에도 만들어 사용한 것을

 

인용하여 사용하였으니, 설명은 생략하겠다.

 

이 뷰 페이저의 올라갈 프래그먼트이다.

 

Frag1

 

public class Frag1 extends Fragment {

    TextView textView;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        ViewGroup viewGroup = (ViewGroup) inflater.inflate(R.layout.viewpager_fragment, container, false);
            textView = viewGroup.findViewById(R.id.textView2); //뷰페이저 안에 텍스트 뷰

        Bottom_Fragment_1 bottom_fragment_1 = new Bottom_Fragment_1(); //바텀 프래그먼트 객체 생성
        bottom_fragment_1.dialog_btn.setOnClickListener(new View.OnClickListener() { //클릭 리스너를 만든다.
            @Override
            public void onClick(View v) {
                CustomDialog dialog = new CustomDialog(getContext()); //커스텀 다이얼로그 객체를 생성 후
                dialog.setDialogListener(new CustomDialog.CustomDialogListener() { //인터페이스를 호출한다.
                    @Override
                    public void onPositiveClicked(String data) { //이곳에서 String데이터를 받아온다.
                        textView.setText(data); //다이얼로그에서 입력한 값 넣기
                        Log.d("값", data);
                    }
                });
            }
        });

        return  viewGroup;
    }
}

여기서 보면, 아까

 

bottom_fragment_1에서 static을 주었던,

 

dialog_btn에 리스너를 주는 것을 볼 수 있다.

 

다른 프래그먼트에서 다른 버튼을 클릭할 수 있다는 점이다.

 

이 사실이 나를 조금 놀라게 했다.

 

그리고 버튼을 클릭할 때

 

CustomDialog 객체를 재정의한다.

 

이 코드는 아래에 있다.

 

 

CustomDialog

public class CustomDialog extends Dialog {


    //Frag1으로 이 버튼을 보내기 위해 public static을 달아주었다.
    public static Dialog dialog; //dialog 객체

    public static Context context;
    public static CustomDialogListener customDialogListener;

    public CustomDialog(Context context) {
        super(context);
        this.context = context;
        dialogStart(); //이 다이얼로그 메서드를 실행될 수 있게 보낸다.
    }


    //인터페이스 설정
    public interface CustomDialogListener{
        void onPositiveClicked(String data);
    }

    //호출할 리스너 초기화
    public void setDialogListener(CustomDialogListener customDialogListener){
        this.customDialogListener = customDialogListener;
    }


    //다이얼로그 안에 버튼에 대한 설정을 할 수 있다.

    public void dialogStart(){
        dialog = new Dialog(getContext());
        dialog.setContentView(R.layout.dialog); //setContentView는 dialog안에 넣는다.
        dialog.show(); //띄우기

        //참조하실때 무조건 앞에 dialog를 붙여주세요.
       Button check_btn = dialog.findViewById(R.id.button);
       Button cancel_btn = dialog.findViewById(R.id.button2);
        EditText editText = dialog.findViewById(R.id.editText);


        check_btn.setOnClickListener(new View.OnClickListener() { //확인 버튼
            @Override
            public void onClick(View v) {
                String data = editText.getText().toString();

                //인터페이스의 함수를 호출하여 변수에 저장된 값들을 프래그먼트로 전달
                customDialogListener.onPositiveClicked(data);
                dialog.dismiss();

            }
        });

        cancel_btn.setOnClickListener(new View.OnClickListener() { //취소 버튼
            @Override
            public void onClick(View v) {
                dialog.dismiss();
            }
        });

    }

}

 

public CustomDialog(Context context) {
        super(context);
        this.context = context;
        dialogStart(); //이 다이얼로그 메서드를 실행될 수 있게 보낸다.
    }


    //인터페이스 설정
    public interface CustomDialogListener{
        void onPositiveClicked(String data);
    }

    //호출할 리스너 초기화
    public void setDialogListener(CustomDialogListener customDialogListener){
        this.customDialogListener = customDialogListener;
    }

 

여기서 중요하게 볼 것은 Context를 받는 생성자와 그 안에, dialogStart() 메서드,

 

그리고 클릭할 때 리스너 인터페이스를 넣어서,

 

Frag1에서 클릭할 때,

 

String data를 보낼 수 있다는 점이다.

 

오늘 배웠던 것 중에 제일 중요한 기능이다.

 

인터페이스의 기능 조차 몰랐던 터라.. 지금에서야 조금 접하고 있는 중인데,

 

이런 좋은 기능이 있는 줄 몰랐다.

 

데이터 전달이면 충분하다.

 

dialog.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">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="75dp"
        android:layout_marginLeft="75dp"
        android:layout_marginTop="317dp"
        android:layout_marginEnd="67dp"
        android:layout_marginRight="67dp"
        android:layout_marginBottom="366dp"
        android:text="보내기"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/button2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="67dp"
        android:layout_marginLeft="67dp"
        android:layout_marginTop="317dp"
        android:layout_marginEnd="83dp"
        android:layout_marginRight="83dp"
        android:layout_marginBottom="366dp"
        android:text="취소"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/button"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="105dp"
        android:layout_marginLeft="105dp"
        android:layout_marginTop="185dp"
        android:layout_marginEnd="97dp"
        android:layout_marginRight="97dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="보낼 데이터 입력"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

마지막으로 다이얼로그의 xml을 작성해주고 나서,

 

실행을 해보겠다.

 

 

이런 식으로 다이얼로그에서 입력한 데이터를 보내기 버튼을 누르고,

 

그 데이터를 같은 프래그먼트 안에 있는 뷰 페이저의 프래그먼트로

 

데이터를 전송할 수 있다.

 

뭔가 되게 까다롭지만, 재미있는 시도였고, 배움이었다.

 

이 밖에도,

 

버스 라이브러리라고 데이터 전달에 유용한 라이브러리가 있다고 들었지만,

 

사용하는데, 방법을 잘 몰라 사용하지 않게 되었다.

 

다음에 기회가 된다면 사용해보도록 하겠다.

 

모든 소스는 깃허브에 올려두었습니다.

 

github.com/qjsqjsaos/Tistrory2

 

qjsqjsaos/Tistrory2

프래그먼트 위에 다이얼로그에서 같은 프래그먼트 위에 있는 뷰페이저의 데이터 전달하기(인터페이스 사용) - qjsqjsaos/Tistrory2

github.com

728x90
반응형

공유하기

facebook twitter kakaoTalk kakaostory naver band
loading