我正在使用片段和 viewpager 制作一个应用程序,它将用户数据发送到主要活动。数据将从多个片段收集并在提交按钮(包含在主活动中)被按下到活动时发送。 示例截图:
我不确定如何获取片段编辑文本数据。我尝试使用 R.findViewById 在提交按钮的 onClick 侦听器中获取它,但似乎我错过了一个重要步骤。我尝试查看视频/教程,但我只能找到在片段中按下按钮时获取数据的适用视频/教程,或者反向操作的视频/教程(片段从活动中获取数据)。
这是我的代码: formActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.google.android.material.tabs.TabLayout;
public class FormActivity extends AppCompatActivity {
private static final String TAG = "PROCESS";
TabLayout tabLayout;
ViewPager viewPager;
//or set to 0 and change it dynamically in the onPageSelected method
private int numFrags = 2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_formactivity);
viewPager = findViewById(R.id.viewPager);
tabLayout = findViewById(R.id.tabLayout);
getTabs();
//Add onPageChangeListener to get the position of the current tab and change the button text based on the position
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
Button back = findViewById(R.id.backButton);
Button next = findViewById(R.id.nextButton);
Button mainReturn = findViewById(R.id.mainReturn);
Button submit = findViewById(R.id.submitButton);
PagerAdapter adapter = viewPager.getAdapter();
//numFrags = viewPager.getAdapter().getCoBunt() -1; - dynamically get new frags
if (position == 0) {
back.setVisibility(View.GONE);
next.setVisibility(View.VISIBLE);
mainReturn.setVisibility(View.VISIBLE);
}
else if (adapter != null && position == numFrags) {
back.setVisibility(View.VISIBLE);
next.setVisibility(View.GONE);
submit.setVisibility(View.VISIBLE);
}
else {
back.setVisibility(View.VISIBLE);
next.setVisibility(View.VISIBLE);
mainReturn.setVisibility(View.GONE);
submit.setVisibility(View.GONE);
}
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
//Add fragments to viewPager using the object ViewPagerAdapter
public void getTabs(){
final ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
new Handler().post(new Runnable() {
@Override
public void run() {
viewPagerAdapter.addFragment(oneFragment.getInstance(),null); // this line can cause crashes
viewPagerAdapter.addFragment(twoFragment.getInstance(),null); // this line can cause crashes
viewPagerAdapter.addFragment(threeFragment.getInstance(),null); // this line can cause crashes
viewPager.setAdapter(viewPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
}
});
}
//METHODS FOR THE BUTTON LISTENERS
public void goBack(View view) {
viewPager.setCurrentItem(viewPager.getCurrentItem()-1);
}
public void goNext(View view) {
viewPager.setCurrentItem(viewPager.getCurrentItem() + 1);
}
public void submitFormEntries(View view) {
Log.d(TAG, "returnToMainMenu: ");
}
public void returnToMainMenu(View view) {
Log.d(TAG, "returnToMainMenu: ");
}
}
ViewPagerAdapter.java
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private List<Fragment> fragmentList = new ArrayList<>(); // this line can cause crashes
private List<String> stringList = new ArrayList<>();
public ViewPagerAdapter(@NonNull FragmentManager fm) {
super(fm);
}
@NonNull
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public int getCount() {
return fragmentList.size();
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return stringList.get(position);
}
public void addFragment(Fragment fragment, String title){
fragmentList.add(fragment); // this line can cause crashes
stringList.add(title);
}
}
oneFragment.java
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class oneFragment extends Fragment {
public static oneFragment getInstance(){
oneFragment oneFragment = new oneFragment();
return oneFragment;
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.page_one, container,false);
return view;
}
}
activity_formactivity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
tools:context=".FormActivity">
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<Button
android:id="@+id/backButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/back"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="goBack"
android:visibility="gone"/>
<Button
android:id="@+id/mainReturn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/mainReturn"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="returnToMainMenu"
android:visibility="visible"/>
<Button
android:id="@+id/nextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/next"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="goNext"/>
<Button
android:id="@+id/submitButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/submit"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="submitFormEntries"
android:visibility="gone"/>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tabBackground="@drawable/tab_selector"
app:tabIndicatorHeight="0dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</RelativeLayout>
page_one.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">
<TextView
android:id="@+id/titleOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="@string/title_one"
android:textColor="@color/colorPrimaryDark"
android:textSize="32sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/questionOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/questionOne"
android:textColor="@color/colorPrimaryDark"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/descriptionOne"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/descriptionOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/descriptionOne"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/answerOne"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<EditText
android:id="@+id/answerOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/answerHintOne"
android:inputType="textMultiLine"
android:maxLines="4"
android:minLines="4"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
我很新,所以任何替代建议以及答案也将不胜感激。
答案 0 :(得分:1)
您可以使用 SharedPreferences 来存储数据并在需要时检索数据。 示例:
在首选项中设置值:
SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit();
editor.putString("key", "your answer");
editor.apply();
从偏好中检索数据:
SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE);
String answer= prefs.getString("key", "");
答案 1 :(得分:1)
如何使用与 ViewModel
相关联的 FormActivity
并将编辑文本值保存在那里
https://developer.android.com/topic/libraries/architecture/viewmodel?gclid=Cj0KCQiA3NX_BRDQARIsALA3fIJFaBMomx-KDhghEHZghVGwGaafvDwMpGzFxQFGm3M3_e0lv9Bzt1UaAoq7EALw_wcB&gclsrc=aw.ds
class FormViewModel : ViewModel() {
val answers: Map<String, String> = mutableMapOf()
}
来自片段
editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
val viewmodel = ViewModelProviders.of(requireActivity()).get(FormViewModel::class.java)
viewModel.answer["SOME_KEY_HERE"] = s.toString()
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
})
从活动中你可以访问这样的价值
ViewModelProvider.of(this).get(FormViewModel::class.java).answer
抱歉,我是用 kotlin 写的,但你应该能够理解这个想法
答案 2 :(得分:1)
实现常规 FragmentPagerAdapter 的正确方法是:
public class ViewPagerAdapter extends FragmentPagerAdapter {
public ViewPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
@Override
public Fragment getItem(int position) {
if(position == 0) return new RulesFragment();
if(position == 1) return new TreeFragment();
if(position == 2) return new PredictionFragment();
throw new IllegalStateException("Unexpected position " + position);
}
@Override
public int getCount() {
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
if(position == 0) return "TREE RULES";
if(position == 1) return "REGRESSION TREE";
if(position == 2) return "PREDICTION";
throw new IllegalStateException("Unexpected position " + position);
}
}
要获取对 ViewPager 创建的 Fragment 的引用,请使用以下 findFragmentByTag
方案:
Fragment fragment = supportFragmentManager.findFragmentByTag("android:switcher:" + viewPager.getId() + ":" + fragmentPosition)
在多个片段之间进行通信的正确方法是使用范围限定为共享范围(在本例中,可能是活动)的 ViewModel。
为此,请参阅https://developer.android.com/codelabs/kotlin-android-training-view-model#0
答案 3 :(得分:0)
使用捆绑包。举个例子:
Fragment fragment = new Fragment();
Bundle bundle = new Bundle();
bundle.putInt(key, value);
fragment.setArguments(bundle);
Bundle 有很多数据类型的 put 方法。看到这个
然后在您的 Fragment 中,使用以下命令检索数据(例如在 onCreate() 方法中):
Bundle bundle = this.getArguments();
if (bundle != null) {
int myInt = bundle.getInt(key, defaultValue);
}
在 bundle.setArguments 中设置第一个片段的值和第二个片段的 onCreate() 使用 bundle.getInt() 获取值 在第二个片段中放置与 bundle.setArguemnts 相同的第一个片段和第二个片段的值,因此在第三个片段中您将获得第一个和第二个片段的值。
片段 1:
Bundle bundle = new Bundle();
bundle.putString("FRAGEMNT1", "VALUE FRAGEMENT 1");
fragment.setArguments(bundle);
在片段 2 的 onCrete()
Bundle bundle = this.getArguments();
if (bundle != null) {
String frag1Value = bundle.getString("FRAGEMNT1");
}
现在将两个值都放在片段 2 中
Bundle bundle = new Bundle();
bundle.putString("FRAGEMNT1", "VALUE FRAGEMENT 1");
bundle.putString("FRAGEMNT2, "VALUE FRAGEMENT 2);
fragment.setArguments(bundle);
在片段 3 onCrete()
Bundle bundle = this.getArguments();
if (bundle != null) {
String frag1Value = bundle.getString("FRAGEMNT1");
String frag2Value = bundle.getString("FRAGEMNT2");
}
现在将两个值都放在片段 3 中
Bundle bundle = new Bundle();
bundle.putString("FRAGEMNT1", "VALUE FRAGEMENT 1");
bundle.putString("FRAGEMNT2, "VALUE FRAGEMENT 2);
bundle.putString("FRAGEMNT3, "VALUE FRAGEMENT 3");
fragment.setArguments(bundle);
现在在 Activit 的 onCrete
Bundle bundle = this.getArguments();
if (bundle != null) {
String frag1Value=bundle.getString("FRAGEMNT1");
String frag2Value=bundle.getString("FRAGEMNT2");
String frag3Value=bundle.getString("FRAGEMNT3");
}