I have created a tabLayout that swipes between two fragments using a viewPager2 + Fragment State Adapter
Within Fragment 2, I have a TextClock within a scroll view.
When I scroll down to the bottom of the page, it keeps jumping to the top if the page
Video link showing issue
Any help would be appreciated
<?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=".BarcodeFragment">
Xml Code:
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="104dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextClock
android:id="#+id/simpleTextClock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:format24Hour="HH : mm : ss"
android:textColor="#color/colorDark"
android:textScaleX=".94"
android:textSize="18sp"
android:textStyle="bold"
app:fontFamily="#font/tlcircular_bold"
app:layout_constraintBottom_toTopOf="#+id/box02"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/box02"
android:layout_width="329dp"
android:layout_height="283.99986dp"
android:layout_marginTop="450dp"
android:background="#drawable/box_rounded_ticket"
android:shadowColor="#00FF0A0A"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
Java Code:
</**
* A simple {#link Fragment} subclass.
*/
public class TicketFragment extends Fragment {
public TicketFragment() {
// Required empty public constructor
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_ticket, container, false);
return rootView;
}
}>
SOLVED
Whenever configuring the height / width of a TextClock - never use 'wrap_content'. I had to reverse engineer my entire app to find such such a simple problem.
My question is: why has this never been flagged before?!
Related
I have a function which inflates a layout and is supposed to manipulate the views contained within the layout. The layout's base element is a ConstraintLayout.
The fragment:
public class HomeFragment extends Fragment {
...
public void myFunction() {
View v = getLayoutInflater().inflate(R.layout.fragment_home, null);
TextView t = (TextView) v.findViewById(R.id.my_text_view);
t.setText("Some other text"); // nothing happens
t.setTextColor(0xFF0000FF); // nothing happens
t.setBackgroundColor(0xFFFF0000); // nothing happens
Log.d("call", "myFunction() was called");
}
}
The layout:
<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/my_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#F0F0F0"
android:text="TextView"
android:textColor="#000"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout/>
The code compiles and runs successfully, but when I call myFunction() nothing happens to the TextView, while the log statement logs successfully. What am I doing wrong?
I'm trying to display a list in a fixed size scrollview, at first it was the first items who weren't showing and I fixed it but now it's the last ones that aren't reachable.
Here is my xml code:
<?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"
android:background="#color/colorPrimary"
tools:context=".ui.home.AperoDetailFragment">
<TextView
android:id="#+id/name_apero"
android:layout_width="156dp"
android:layout_height="53dp"
android:textSize="18sp"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<TextView
android:id="#+id/date_apero"
android:layout_width="238dp"
android:layout_height="53dp"
android:textSize="18sp"
android:ems="10"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.907"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<ScrollView
android:id="#+id/ingredient_apero"
android:layout_width="410dp"
android:layout_height="607dp"
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/ingredient_title_apero"
app:layout_constraintVertical_bias="0.0">
<LinearLayout
android:id="#+id/vertical_layout_ingredient"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</ScrollView>
<TextView
android:id="#+id/ingredient_title_apero"
android:layout_width="115dp"
android:layout_height="28dp"
android:text="Liste d'achat:"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.005"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.125" />
</androidx.constraintlayout.widget.ConstraintLayout>
and here is my java code to populate the list:
public class AperoDetailFragment extends Fragment {
private View root;
private Apero detailApero;
public AperoDetailFragment(Apero apero) {
this.detailApero = apero;
}
#Override
public View onCreateView(#NonNull final LayoutInflater inflater,
final ViewGroup container, Bundle savedInstanceState) {
root = inflater.inflate(R.layout.fragment_detail_apero, container, false);
TextView name = (TextView)root.findViewById(R.id.name_apero);
name.setText(detailApero.getName());
TextView date = (TextView)root.findViewById(R.id.date_apero);
date.setText(detailApero.getDate());
LinearLayout ll = (LinearLayout)root.findViewById(R.id.vertical_layout_ingredient);
LinearLayout a = new LinearLayout(root.getContext());
a.setOrientation(LinearLayout.VERTICAL);
for(int i = 0; i < 20; i++)
{
Button b = new Button(root.getContext());
b.setText("Button "+i);
a.addView(b);
}
ll.addView(a);
return root;
}
}
When I scroll I can reach the number 16 but not the other, it's like they are under the layout I don't really know how to explain better.
So the question is how can I scroll my list until the last items ?
There are a few issues with your code: first and foremost if you want to display data as a list you should use a RecyclerView instead of a ScrollView. ScrollViews are there to allow the content (or part of it) in your activity/fragment to be scrollable.
Second, it's not a good practice to set specific sizes to your views, especially when using ConstraintLayout.
Third, onCreateView is meant to be a method that will simply inflate your fragment's layout and return it as a View. For handling the UI, use onViewCreated. That way you will guarantee that your UI will never be handled before your fragment is actually attached to the activity.
So answering your question, use a RecyclerView to display your items as a list instead of the ScrollView and you'll be good to go from there
The layout of my StartupPreference is defined with only one ViewPager as:
<?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"
/>
and the associated activity associates this as:
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;
}
}
}
The problem I am having is that I'm not getting it how to access different Views associated with the ViewPager. Since both the layout of the fragments include a common layout called dot_animation.xml using the <include...> tag, but the code in the onPageSelected method above updates only the first page, and if I use different ids in the <include...> like:
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"
/>
...
and I use these ids to update the ImageView then I get a NullPointer Exception.(I use the code in the activity)
So, what can I do to access the different Views in the respective pages of the ViewPager?
The layout of the fragments are given below:
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>
First of all you need to update the view in fragmnet on onViewCreated.
the reason that you cant update other views is the viewpager only shows the current fragment.and the reason for nullpointexception also is that the other view are not loaded into the activity by viewpager.(You may also want to check if the correct layout is being called in the onCreateView method.) If you want to load all of them even if they are out of the screen you can use viewPager.setOffscreenPageLimit(); but this lose the viewpager purpose. so what i suggest is to create call back to communicate with your fragment and send data through callbacks and update your view inside of there fragment. also this make your activity less messy.
Update :
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.
I want to display a Progressbar in my LoginFragment for testing purposes however after I connect my view variables in the OnCreateView Callback in my LoginFragment, my app shuts down and its due to:
Attempt to invoke virtual method 'void android.widget.ProgressBar.setVisibility(int)' on a null object reference
But what's driving me nuts is that this is the only View that throws a NPE, all my other views I am able to manipulate and reference without a problem. I also tried to use a Progressbar in the LoginActivity that hosts the LoginFragment and the Progressbar worked as expected, but why not in the fragment ??
I attached the code xml and fragment code corresponding to the LoginFragment
public class LoginFragment extends Fragment {
private AutoCompleteTextView name;
private EditText password;
private ProgressBar progressBar;
//......... Skipped For Brevity .........
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.login_fragment, container, false);
v.setBackgroundResource(R.drawable.album_jazz_blues);
name = v.findViewById(R.id.username);
password = v.findViewById(R.id.password);
progressBar = v.findViewById(R.id.progress_bar);
//progressBar.setVisibility(View.VISIBLE); <-------- THROWS NPE
return v;
}
}
XML:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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.support.constraint.ConstraintLayout
android:id="#+id/constraint_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/login_parent_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:padding="16dp"
android:orientation="vertical"
tools:layout_alignParentTop="true"
tools:layout_alignParentStart="true" >
<AutoCompleteTextView
android:id="#+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"
android:hint="#string/email"
android:maxLines="1"
android:singleLine="true" />
<EditText
android:id="#+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/password"
android:inputType="textPassword"
android:maxLines="1"
android:singleLine="true"
tools:ignore="Autofill" />
</LinearLayout>
</android.support.constraint.ConstraintLayout>
<ProgressBar
style="#style/Widget.AppCompat.ProgressBar"
android:layout_gravity="center"
android:indeterminate="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/progress_bar">
</ProgressBar>
What Am I missing here ?
As Aaron in the comments pointed out, I had two different layout folders a normal folder and v-26 folder which did not necessarily mirror each other so what I did was assign the folders the exact same elements and attributes with their corresponding values with the exception of
EditTextandroid:importantForAutofill
autofill attribute, in v-26 android:importantForAutofill="no and in my regular layout folder tools:ignore="Autofill"
I have a very simple Dialog:
On click of the button I would like to toggle visibility of the second EditText:
public class SomeDialog extends DialogFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.some_dialog, container, false);
EditText editSecond = root.findViewById(R.id.text_second);
Button buttonOk = root.findViewById(R.id.button_ok);
buttonOk.setOnClickListener(v -> {
editSecond.setVisibility(editSecond.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE);
});
return root;
}
}
I would like it to be animated smoothly, so I set "animateLayoutChanges" to "true":
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:animateLayoutChanges="true"
>
<TextView
android:id="#+id/titleText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
android:padding="8dp"
android:text="Title"
android:textAppearance="#style/TextAppearance.AppCompat.Large.Inverse"
android:textSize="18sp"
/>
<EditText
android:id="#+id/text_first"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="First"
/>
<EditText
android:id="#+id/text_second"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Second"
/>
<Button
android:id="#+id/button_ok"
style="#style/Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:text="Ok"
/>
</LinearLayout>
The dialog gets animated, but unfortunately not in the correct order.
What happens:
the TextEdit vanishes
the Dialog height snaps (instantly) to the smaller height
the Button moves up (animated)
So between 2) and 3) the button is not visible and slowly slides into the (already smaller) dialog from offscreen (bottom).
What can be done about this?
(Code Sample works and can be copy/pasted into Android Studio as is)