在 ViewPager 的不同页面访问不同的 children
accessing different children in different pages of ViewPager
我的 StartupPreference
的布局只用一个 ViewPager
定义为:
<?xml version="1.0" encoding="utf-8"?>
<androidx.viewpager.widget.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/startPref_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
和关联的 activity 将其关联为:
public class StartupPreference extends AppCompatActivity implements StartupPrefFrag_interfaces{
private final static int no_of_prefs = 2;
private LinearLayout dot_animation_holder;
private static int temp_count = 0;
public void ViewUpdater(View updatedView){
dot_animation_holder = (LinearLayout) updatedView;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_startup_preference);
//we're not using the layout natively, but using Fragment's layout
//but setContentView is required -> it is accessed by : R.id.startPref_pager
dot_animation_holder= findViewById(R.id.dot_animation_holder);
StartPrefPagerAdapter prefPagerAdapter =
new StartPrefPagerAdapter(getSupportFragmentManager());
ViewPager StartPref_Viewpager = findViewById(R.id.startPref_pager);
StartPref_Viewpager.setAdapter(prefPagerAdapter);
StartPref_Viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
((ImageView)(findViewById(R.id.dot_animation_holder).findViewById(R.id.page1))).setImageResource(R.drawable.active_dot);
((ImageView)(findViewById(R.id.dot_animation_holder).findViewById(R.id.page2))).setImageResource(R.drawable.inactive_dot);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
private class StartPrefPagerAdapter extends FragmentPagerAdapter {
public StartPrefPagerAdapter(FragmentManager fm){
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@Override
public int getCount(){
return StartupPreference.no_of_prefs;//no. of preference pages
}
@Override
public Fragment getItem(int position) {
switch (position){
case 0:
return new Frag_StartPref_Layout();
case 1:
return new Frag_StartPref_Theme();
}
return null;
}
}
}
我遇到的问题是我不知道如何访问与 ViewPager
关联的不同 View
。由于 fragment
的 layout
都包含一个使用 <include...>
标记的名为 dot_animation.xml
的公共 layout
,但是 中的代码 onPageSelected
上面的方法只更新第一页,如果我在 <include...>
中使用不同的 id
s,比如:
fragment_startpref_layout.xml:
...
<include
layout="@layout/dot_animation"
android="@+id/dot_animation_holder1"
/>
...
fragment_startpref_theme.xml
...
<include
layout="@layout/dot_animation"
android="@+id/dot_animation_holder2"
/>
...
并且我使用这些 id
更新 ImageView
然后我得到一个 NullPointer
异常。(我使用 activity
中的代码)
那么,我怎样才能访问 ViewPager
的各个页面中的不同 View
?
片段的布局如下:
fragment_startpref_layout.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:id="@+id/C_startPref_layout"
android:layout_height="match_parent"
android:layout_width="match_parent"
>
<ImageView
android:id="@+id/startPref_Layout"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toTopOf="@+id/startPref_layout_info"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@mipmap/ic_launcher" />
<TextView
android:id="@+id/startPref_layout_info"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:gravity="center"
android:text="@string/Frag_startPref_layout_info"
android:textSize="25sp"
app:layout_constraintBottom_toTopOf="@+id/startPref_layout_select1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent=".125"
app:layout_constraintStart_toStartOf="parent" />
<RadioGroup
android:id="@+id/startPref_layout_select1"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@+id/dot_animation_holder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent=".125"
app:layout_constraintStart_toStartOf="parent">
<RadioButton
android:id="@+id/radioButton1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:checked="true"
android:text="@string/Frag_startPref_Radio1"
android:textSize="15sp" />
<RadioButton
android:id="@+id/radioButton2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/Frag_startPref_Radio2"
android:textSize="15sp" />
</RadioGroup>
<include
layout="@layout/dot_animation"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
fragment_theme_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/C_startPref_theme"
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_height="match_parent"
android:layout_width="match_parent"
>
<ImageView
android:id="@+id/startPref_Theme"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toTopOf="@+id/startPref_layout_info"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@mipmap/ic_launcher" />
<TextView
android:id="@+id/startPref_layout_info"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:gravity="center"
android:text="@string/Frag_startPref_layout_info"
android:textSize="25sp"
app:layout_constraintBottom_toTopOf="@+id/startPref_layout_select2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent=".125"
app:layout_constraintStart_toStartOf="parent" />
<RadioGroup
android:id="@+id/startPref_layout_select2"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@+id/dot_animation_holder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent=".125"
app:layout_constraintStart_toStartOf="parent">
<RadioButton
android:id="@+id/radioButton1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:checked="true"
android:text="@string/Frag_startPref_Radio1"
android:textSize="15sp" />
<RadioButton
android:id="@+id/radioButton2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/Frag_startPref_Radio2"
android:textSize="15sp" />
</RadioGroup>
<include
layout="@layout/dot_animation"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
首先,您需要在 onViewCreated
上更新 fragmnet
中的 view
。
您无法更新其他视图的原因是 viewpager 仅显示当前 fragment.and nullpointexception 的原因也是其他视图未被 viewpager 加载到 activity。(您可能还想检查如果在 onCreateView
方法中调用了正确的布局。)如果你想加载所有它们,即使它们不在屏幕上,你可以使用 viewPager.setOffscreenPageLimit();
但这失去了 viewpager 的目的。所以我的建议是创建回调以与您的片段通信并通过回调发送数据并更新您在片段内的视图。这也让你的 activity 不那么凌乱。
更新:
example of using ViewPager with multiple layouts
Document About setOffscreenPageLimit
Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state. Pages beyond
this limit will be recreated from the adapter when needed.
This is offered as an optimization. If you know in advance the number
of pages you will need to support or have lazy-loading mechanisms in
place on your pages, tweaking this setting can have benefits in
perceived smoothness of paging animations and interaction. If you have
a small number of pages (3-4) that you can keep active all at once,
less time will be spent in layout for newly created view subtrees as
the user pages back and forth.
You should keep this limit low, especially if your pages have complex
layouts. This setting defaults to 1.
我的 StartupPreference
的布局只用一个 ViewPager
定义为:
<?xml version="1.0" encoding="utf-8"?>
<androidx.viewpager.widget.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/startPref_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
和关联的 activity 将其关联为:
public class StartupPreference extends AppCompatActivity implements StartupPrefFrag_interfaces{
private final static int no_of_prefs = 2;
private LinearLayout dot_animation_holder;
private static int temp_count = 0;
public void ViewUpdater(View updatedView){
dot_animation_holder = (LinearLayout) updatedView;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_startup_preference);
//we're not using the layout natively, but using Fragment's layout
//but setContentView is required -> it is accessed by : R.id.startPref_pager
dot_animation_holder= findViewById(R.id.dot_animation_holder);
StartPrefPagerAdapter prefPagerAdapter =
new StartPrefPagerAdapter(getSupportFragmentManager());
ViewPager StartPref_Viewpager = findViewById(R.id.startPref_pager);
StartPref_Viewpager.setAdapter(prefPagerAdapter);
StartPref_Viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
((ImageView)(findViewById(R.id.dot_animation_holder).findViewById(R.id.page1))).setImageResource(R.drawable.active_dot);
((ImageView)(findViewById(R.id.dot_animation_holder).findViewById(R.id.page2))).setImageResource(R.drawable.inactive_dot);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
private class StartPrefPagerAdapter extends FragmentPagerAdapter {
public StartPrefPagerAdapter(FragmentManager fm){
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@Override
public int getCount(){
return StartupPreference.no_of_prefs;//no. of preference pages
}
@Override
public Fragment getItem(int position) {
switch (position){
case 0:
return new Frag_StartPref_Layout();
case 1:
return new Frag_StartPref_Theme();
}
return null;
}
}
}
我遇到的问题是我不知道如何访问与 ViewPager
关联的不同 View
。由于 fragment
的 layout
都包含一个使用 <include...>
标记的名为 dot_animation.xml
的公共 layout
,但是 中的代码 onPageSelected
上面的方法只更新第一页,如果我在 <include...>
中使用不同的 id
s,比如:
fragment_startpref_layout.xml:
...
<include
layout="@layout/dot_animation"
android="@+id/dot_animation_holder1"
/>
...
fragment_startpref_theme.xml
...
<include
layout="@layout/dot_animation"
android="@+id/dot_animation_holder2"
/>
...
并且我使用这些 id
更新 ImageView
然后我得到一个 NullPointer
异常。(我使用 activity
中的代码)
那么,我怎样才能访问 ViewPager
的各个页面中的不同 View
?
片段的布局如下:
fragment_startpref_layout.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:id="@+id/C_startPref_layout"
android:layout_height="match_parent"
android:layout_width="match_parent"
>
<ImageView
android:id="@+id/startPref_Layout"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toTopOf="@+id/startPref_layout_info"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@mipmap/ic_launcher" />
<TextView
android:id="@+id/startPref_layout_info"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:gravity="center"
android:text="@string/Frag_startPref_layout_info"
android:textSize="25sp"
app:layout_constraintBottom_toTopOf="@+id/startPref_layout_select1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent=".125"
app:layout_constraintStart_toStartOf="parent" />
<RadioGroup
android:id="@+id/startPref_layout_select1"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@+id/dot_animation_holder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent=".125"
app:layout_constraintStart_toStartOf="parent">
<RadioButton
android:id="@+id/radioButton1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:checked="true"
android:text="@string/Frag_startPref_Radio1"
android:textSize="15sp" />
<RadioButton
android:id="@+id/radioButton2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/Frag_startPref_Radio2"
android:textSize="15sp" />
</RadioGroup>
<include
layout="@layout/dot_animation"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
fragment_theme_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/C_startPref_theme"
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_height="match_parent"
android:layout_width="match_parent"
>
<ImageView
android:id="@+id/startPref_Theme"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toTopOf="@+id/startPref_layout_info"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@mipmap/ic_launcher" />
<TextView
android:id="@+id/startPref_layout_info"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:gravity="center"
android:text="@string/Frag_startPref_layout_info"
android:textSize="25sp"
app:layout_constraintBottom_toTopOf="@+id/startPref_layout_select2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent=".125"
app:layout_constraintStart_toStartOf="parent" />
<RadioGroup
android:id="@+id/startPref_layout_select2"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@+id/dot_animation_holder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent=".125"
app:layout_constraintStart_toStartOf="parent">
<RadioButton
android:id="@+id/radioButton1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:checked="true"
android:text="@string/Frag_startPref_Radio1"
android:textSize="15sp" />
<RadioButton
android:id="@+id/radioButton2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/Frag_startPref_Radio2"
android:textSize="15sp" />
</RadioGroup>
<include
layout="@layout/dot_animation"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
首先,您需要在 onViewCreated
上更新 fragmnet
中的 view
。
您无法更新其他视图的原因是 viewpager 仅显示当前 fragment.and nullpointexception 的原因也是其他视图未被 viewpager 加载到 activity。(您可能还想检查如果在 onCreateView
方法中调用了正确的布局。)如果你想加载所有它们,即使它们不在屏幕上,你可以使用 viewPager.setOffscreenPageLimit();
但这失去了 viewpager 的目的。所以我的建议是创建回调以与您的片段通信并通过回调发送数据并更新您在片段内的视图。这也让你的 activity 不那么凌乱。
更新:
example of using ViewPager with multiple layouts
Document About setOffscreenPageLimit
Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state. Pages beyond this limit will be recreated from the adapter when needed.
This is offered as an optimization. If you know in advance the number of pages you will need to support or have lazy-loading mechanisms in place on your pages, tweaking this setting can have benefits in perceived smoothness of paging animations and interaction. If you have a small number of pages (3-4) that you can keep active all at once, less time will be spent in layout for newly created view subtrees as the user pages back and forth.
You should keep this limit low, especially if your pages have complex layouts. This setting defaults to 1.