#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
.