Как я могу поместить фрагмент внутри вкладки?

#java #android #xml #android-studio #android-fragments

Вопрос:

В моем проекте Android Studio у меня есть фрагмент, который я создал для отображения страницы профиля приложения для знакомств. У меня также есть активность регистрации, которая используется вместо основной активности, которая ведет к другой активности, называемой второй активностью. Мой фрагмент называется фрагментом профиля. То, что я пытаюсь сделать, — это поместить фрагмент профиля в первую вкладку моего второго действия. Прямо сейчас, когда я запускаю проект и создаю действительный профиль знакомств, я получаю фрагмент в фоновом режиме со вторым действием с его вкладками на переднем плане. Каков самый простой способ добавить мой фрагмент на вкладку с тем, что у меня есть прямо сейчас? Я прикрепил код для xml — кода и java-кода для второго действия и фрагмента профиля. Я также прикреплю ссылку на свой github, если это поможет ответить на мой вопрос:

https://github.com/alasali1/Form

Ниже приведен код для моего второго действия:

 package com.example.form;

import android.os.Bundle;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayout;

import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.viewpager.widget.ViewPager;
import androidx.appcompat.app.AppCompatActivity;

import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

import com.example.form.ui.main.SectionsPagerAdapter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;

public class SecondActivity extends AppCompatActivity {

private static final String TAG = SecondActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_second);
    SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
    ViewPager viewPager = findViewById(R.id.view_pager);
    viewPager.setAdapter(sectionsPagerAdapter);
    TabLayout tabs = findViewById(R.id.tabs);
    tabs.setupWithViewPager(viewPager);
    FloatingActionButton fab = findViewById(R.id.fab);

    //fragment
    ProfileFragment profileFragment = new ProfileFragment();
    FragmentManager manager = getSupportFragmentManager();
    FragmentTransaction transaction = manager.beginTransaction();
    transaction.add(R.id.fragment_profile, profileFragment, "profileFragment");
    transaction.commit();
    Log.i(TAG, "onCreate()");

    //Get the bundle
    Bundle bundle = getIntent().getExtras();
    String stringDate = bundle.getString("date");
    String stringName = bundle.getString("name");
    String stringJob = bundle.getString("job");
    String stringDescription = bundle.getString("description");
    //set arguments
    profileFragment.setArguments(bundle);

    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });
}
//turn date string into date object
public static Calendar convertDate(String stringDate) throws ParseException {
    SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

    Calendar date = Calendar.getInstance();
    date.setTime(sdf.parse(stringDate));
    return date;
}

public static boolean checkAge(Calendar date){
    Calendar today = Calendar.getInstance();
    int checkYear = today.get(Calendar.YEAR) -18;
    int yob = date.get(Calendar.YEAR);
    int mob = date.get(Calendar.MONTH);
    int dob = date.get(Calendar.DAY_OF_MONTH);
    if(date.after(today)){
        return false;
    }
    if(yob > checkYear){
        return false;
    } else if(mob > today.get(Calendar.MONTH)){
        return false;
    } else if(dob > today.get(Calendar.DAY_OF_MONTH)){
        return false;
    } else{
        return true;
    }

}


@Override
protected void onRestart() {
    super.onRestart();
    Log.i(TAG, "onRestart()");
}

@Override
protected void onStart() {
    super.onStart();
    Log.i(TAG, "onStart()");
}

@Override
protected void onResume() {
    super.onResume();
    Log.i(TAG, "onResume()");
}

@Override
protected void onPause() {
    super.onPause();
    Log.i(TAG, "onPause()");
}

@Override
protected void onStop() {
    super.onStop();
    Log.i(TAG, "onStop()");
}

@Override
protected void onDestroy() {
    super.onDestroy();
    Log.i(TAG, "onDestroy()");
}
}
 

В то время как java-код для моего фрагмента :

 package com.example.form;

import android.os.Bundle;

import androidx.fragment.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.text.ParseException;
import java.util.Calendar;


public class ProfileFragment extends Fragment {
TextView textView, jobView, ageView, descriptionView;
ImageView imageView;

public ProfileFragment() {
    // Required empty public constructor
}



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

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_profile, container, false);

    String stringDate = getArguments().getString("date");
    String stringName = getArguments().getString("name");
    String stringJob = getArguments().getString("job");
    String stringDescription = getArguments().getString("description");

    //make imageView
    imageView = v.findViewById(R.id.imageView);
    //make textview
    textView = v.findViewById(R.id.textView);
    //make job textview
    jobView = v.findViewById(R.id.job);
    //add input to jobView
    if(stringJob.equals("")){
        jobView.append("N/A");
    } else{
        jobView.setText(stringJob);
    }
    //make descriptionView
    descriptionView = v.findViewById(R.id.description);
    //add input to descriptionView
    descriptionView.append(" "  stringDescription);
    //make ageView
    ageView= v.findViewById(R.id.age);
    //make age variable
    int age = 0;
    //Get age
    try {
        Calendar birth = ConfirmActivity.convertDate(stringDate);
        Calendar today = Calendar.getInstance();
        if(today.get(Calendar.DAY_OF_YEAR) < birth.get(Calendar.DAY_OF_YEAR)){
            age= today.get(Calendar.YEAR) - birth.get(Calendar.YEAR) - 1;
        }
        else{
            age= today.get(Calendar.YEAR) - birth.get(Calendar.YEAR);
        }
    } catch (ParseException e) {
        e.printStackTrace();
    }
    //set age
    ageView.append(String.valueOf(age));
    //convert date
    try {
        Calendar date = ConfirmActivity.convertDate(stringDate);
        //compare date
        if(ConfirmActivity.checkAge(date)){
            textView.setText(" "  stringName  " Thank you for signing up");
        }
        else{
            imageView.equals(null);
            textView.append(" Please try again when you're older");
            jobView.equals("");
            ageView.equals("");
        }
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return v;


}
}
 

The XML for my second activity is :

 <?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 
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=".SecondActivity">

<FrameLayout
    android:id="@ id/fragment_profile"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />

<com.google.android.material.appbar.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/Theme.Form.AppBarOverlay">


    <TextView
        android:id="@ id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:minHeight="?actionBarSize"
        android:padding="@dimen/appbar_padding"
        android:text="@string/app_name"
        android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title" />

    <com.google.android.material.tabs.TabLayout
        android:id="@ id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary">

    </com.google.android.material.tabs.TabLayout>
</com.google.android.material.appbar.AppBarLayout>

<androidx.viewpager.widget.ViewPager
    android:id="@ id/view_pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />

<com.google.android.material.floatingactionbutton.FloatingActionButton
    android:id="@ id/fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom|end"
    android:layout_margin="@dimen/fab_margin"
    app:srcCompat="@android:drawable/ic_dialog_email" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
 

В то время как xml для фрагмента является :

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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=".ConfirmActivity"
android:orientation="vertical"
android:weightSum="4">



    <ImageView
    android:id="@ id/imageView"
    android:layout_width="203dp"
    android:layout_height="100dp"
    android:layout_gravity="center_horizontal"
    android:layout_weight="1"
    android:src="@drawable/blank_pic"
    />
    <TextView
    android:id="@ id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hi"
    android:layout_gravity="center_horizontal"
    />

    <TextView
    android:id="@ id/job"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/job"
    android:layout_gravity="center_horizontal"
    />

    <TextView
    android:id="@ id/age"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/age"
    android:layout_gravity="center_horizontal"
    android:layout_weight="1"
    />

    <TextView
    android:id="@ id/description"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:text="@string/description"
    android:layout_weight="1"
    />
 </LinearLayout>
 

Вот скриншот, показывающий мою проблему. Фрагмент, который я хочу поместить на вкладку, статичен в фоновом режиме, в то время как строка hello world на переднем плане находится внутри вкладок, поэтому они меняются, когда я нажимаю на новую вкладку. Я хочу поместить свой фрагмент внутри первой вкладки, а не в фоновом режиме, если это имеет смысл:
введите описание изображения здесь

введите описание изображения здесь

Комментарии:

1. Короткий ответ заключается в том, что SectionsPagerAdapter следует управлять тем, какой фрагмент отображается для какой вкладки. Не создавайте ProfileFragment непосредственно в действии. Вместо этого создайте его внутри SectionsPagerAdapter для вкладки, где он должен отображаться.

Ответ №1:

Проблема в том, что здесь:

     ProfileFragment profileFragment = new ProfileFragment();
    FragmentManager manager = getSupportFragmentManager();
    FragmentTransaction transaction = manager.beginTransaction();
    transaction.add(R.id.fragment_profile, profileFragment, "profileFragment");
    transaction.commit();
 

Этот код создает экземпляр ProfileFragment и добавляет его непосредственно в действие. Вместо этого вы должны создать фрагменты, которые принадлежат вкладке в SectionsPagerAdapter и использовать ее для управления тем, какой фрагмент отображается в соответствии с выбранной вкладкой.

Комментарии:

1. Спасибо, я думаю, что это решение проблемы, которую я ищу, но я не знаю, как его применить. Когда я смотрю учебники о том, как это сделать, кажется, что они пишут класс SectionsPagerAdapter и переопределяют метод GetItems (). Поскольку у меня был автоматически сгенерированный класс SectionsPagerAdapter, нужно ли мне вносить изменения и переопределять метод этого класса или есть простой способ создать фрагмент в SectionsPagerAdapter?

2. @Calas У вас правильная идея. Я предлагаю вам следовать руководству по ViewPager и адаптировать его к вашим потребностям. Руководство по официальным документам для Android — хорошее место для начала.

Ответ №2:

Хм, если я правильно понял, вы хотите использовать пейджер просмотра для просмотра страниц каждой вкладки.

Вам не нужен «Вывод кадров», потому что адаптер ViewPager2 переключает фрагмент, передавая FragmentManager адаптеру ViewPager2.

в xml переключите ViewPager на ViewPager2.

 <androidx.viewpager2.widget.ViewPager2
    android:id="@ id/view_pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
 

Создайте новый класс, расширяющий адаптер FragmentStateAdapter, в этом классе вы будете указывать количество фрагментов, которые ViewPager2 будет использовать для перемещения между ними.

 public class FragmentAdapter_ViewPager extends FragmentStateAdapter {


    public FragmentStateAdapter_ViewPager(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {

        super(fragmentManager, lifecycle);

    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        switch (position) {
            case 0://FIRST TAB
                return new Fragment_Two();
            case 1://SECOND TAB
                return new Fragment_Three();
            default:
                return new Profile_Fragment();

        }

        return null;
    }

    @Override
    public int getItemCount() {
        return 3;
    }
}
 

Если у вас есть более одного фрагмента для отображения на вкладках, которые вы можете увеличить в методе «createFragment ()», просто не забудьте указать, сколько фрагментов будет отображаться в методе «getItemCount()».

Теперь в SecoundActivity вы можете настроить новый ViewPager2 с адаптером и новым средством компоновки, которые синхронизируют их вместе.

//Адаптер ViewPager2, который будет переключать фрагменты

 viewPager2.setAdapter(new FragmentStateAdapter_ViewPager(getChildFragmentManager(), getLifecycle()));
 

//Средство компоновки, которое будет синхронизироваться с вкладками

 new TabLayoutMediator(tabLayout, viewPager2, new TabLayoutMediator.TabConfigurationStrategy() {
            @Override
            public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
                tab.setText("TAB NAME"[position]);
            }
        }).attach();
 

Попробуйте заглянуть на СТРАНИЦУ РУКОВОДСТВА в:
Создание видов прокрутки с вкладками с помощью ViewPager2

Комментарии:

1. Привет, Матеус, спасибо тебе за твое предложение. Чтобы уточнить, вкладки в моем представлении работают правильно и меняются по щелчку, но моя проблема в том, что мой фрагмент не находится внутри вкладки, скорее он статичен в фоновом режиме, и когда я меняю вкладки, на переднем плане меняются только строки hello world по умолчанию. Я опубликую несколько скриншотов, чтобы показать, что я имею в виду.

2. @Calas, то фрагмент не управляется должным образом SectionsPagerAdapter .