I'm currently making a soundboard app on android studio which has a ton of fragments. The first page on my tab layout is just a normal button view, but my second tabView has another fragmentView within it. The goal is for the first page to just show some normal sounds, and the second tab to have multiple operators to choose specific soundboards for.
Anyways, the app seems to work fine. I can switch from the main tab to the operator tab, and even select operator soundboard pages and be moved to their fragments. However as soon as I try to switch fragments (through my tabview) my app crashes and I get the error:
"Fragment operatorTab{4623fc9} (312d4e58-458c-4f47-8fa3-794fe15f0536)} not attached to a context."**
**at com.jkcarraher.rainbowsixsoundboard.operatorTab.resetAllButtons(operatorTab.java:113)
at com.jkcarraher.rainbowsixsoundboard.operatorTab.access$000(operatorTab.java:31)
at com.jkcarraher.rainbowsixsoundboard.operatorTab$2.onScrollChanged(operatorTab.java:107)
I attached my code below, please let me know if you have any ideas!
MainActivity.java
import android.graphics.Color;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.widget.Adapter;
import android.widget.TextView;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.initialization.InitializationStatus;
import com.google.android.gms.ads.initialization.OnInitializationCompleteListener;
import com.google.android.material.tabs.TabLayout;
import androidx.viewpager.widget.ViewPager;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private SectionsPageAdapter mSectionsPageAdapter;
private ViewPager mViewPager;
private TabLayout tabLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeAds();
makeSixYellow();
//Create ViewPager (that houses all fragments)
mSectionsPageAdapter = new SectionsPageAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.view_pager);
setUpViewPager(mViewPager);
//Add & customize tabs
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setTabTextColors(Color.WHITE, Color.WHITE);
tabLayout.setupWithViewPager(mViewPager);
tabLayout.getTabAt(0).setText("Utility");
tabLayout.getTabAt(1).setText("Voice Lines");
checkPageChange();
}
private void setUpViewPager(ViewPager viewPager) {
SectionsPageAdapter adapter = new SectionsPageAdapter(getSupportFragmentManager());
adapter.addFragment(new utilityTab(), "Utility");
adapter.addFragment(new voiceLinesView(), "Voice Lines");
viewPager.setAdapter(adapter);
}
private void makeSixYellow(){
TextView textView = findViewById(R.id.titleText);
String text = "R6 Soundboard";
SpannableString ss = new SpannableString(text);
ForegroundColorSpan fcsYellow = new ForegroundColorSpan(Color.rgb(255,236,141));
ss.setSpan(fcsYellow, 1,2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(ss);
}
private void initializeAds(){
MobileAds.initialize(this, new OnInitializationCompleteListener() {
#Override
public void onInitializationComplete(InitializationStatus initializationStatus) {
}
});
}
private void checkPageChange(){
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
utilityTab.resetAllButtons();
}
#Override
public void onPageSelected(int position) {
utilityTab.resetAllButtons();
}
#Override
public void onPageScrollStateChanged(int state) {
utilityTab.resetAllButtons();
}
});
}
}
activity_main.xml
<?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=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorHeader"
android:theme="#style/AppTheme.AppBarOverlay">
<TextView
android:id="#+id/titleText"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/avenir"
android:gravity="center_horizontal"
android:text="R6 Soundboard"
android:textColor="#FFF"
android:textSize="30sp" />
<com.google.android.material.tabs.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabTextColor="#fff"
android:background="#color/colorHeader" />
</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"
android:background="#color/colorBody"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
voiceLinesView.java (contains fragments so I can select an operator and it will take me to their soundboard fragment)
package com.jkcarraher.rainbowsixsoundboard;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.viewpager.widget.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.material.tabs.TabLayout;
public class voiceLinesView extends Fragment {
private SectionsPageAdapter voiceLinesSectionsPageAdapter;
private ViewPager voiceLinesViewPager;
public voiceLinesView() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_voice_lines_view, container, false);
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.voiceLinesFrame, new operatorTab());
fragmentTransaction.commit();
return view;
}
}
fragment_voice_lines_view.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"
tools:context=".voiceLinesView">
<FrameLayout
android:id="#+id/voiceLinesFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
operatorTab.java
package com.jkcarraher.rainbowsixsoundboard;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Rect;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import soup.neumorphism.NeumorphCardView;
import soup.neumorphism.ShapeType;
import static android.view.MotionEvent.ACTION_MOVE;
public class operatorTab extends Fragment {
private ScrollView scrollView;
public static RelativeLayout KapkanButton;
public static RelativeLayout GlazButton;
public static RelativeLayout FuzeButton;
public static RelativeLayout TachankaButton;
voiceLinesView voiceLinesView = new voiceLinesView();
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_operator_tab, container, false);
//Initialize ScrollView
scrollView = view.findViewById(R.id.operatorScrollView);
//Initialize buttons 1-4
KapkanButton = view.findViewById(R.id.kapkanButton);
GlazButton = view.findViewById(R.id.glazButton);
FuzeButton = view.findViewById(R.id.fuzeButton);
TachankaButton = view.findViewById(R.id.tachankaButton);
//Make buttons 1-6 pressable
initPressableButton(KapkanButton);
initPressableButton(GlazButton);
initPressableButton(FuzeButton);
initPressableButton(TachankaButton);
scrollResetListener();
return view;
}
#SuppressLint("ClickableViewAccessibility")
private void initPressableButton(final RelativeLayout relativeLayout) {
relativeLayout.setBackgroundColor(getResources().getColor(R.color.colorBody));
final Rect r = new Rect();
relativeLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
// get the View's Rect relative to its parent
view.getHitRect(r);
// offset the touch coordinates with the values from r
// to obtain meaningful coordinates
final float x = event.getX() + r.left;
final float y = event.getY() + r.top;
if(event.getAction() == MotionEvent.ACTION_DOWN) {
relativeLayout.setBackgroundColor(getResources().getColor(R.color.colorButtonPressed));
return true;
} else if(event.getAction() == MotionEvent.ACTION_UP) {
if (r.contains((int) x, (int) y)) {
relativeLayout.setBackgroundColor(getResources().getColor(R.color.colorBody));
//On Click Up
FragmentTransaction fr = getFragmentManager().beginTransaction();
fr.replace(R.id.voiceLinesFrame, new kapkanVoiceLines());
fr.commit();
}
}else if(event.getAction() == ACTION_MOVE){
if (!r.contains((int) x, (int) y)) {
relativeLayout.setBackgroundColor(getResources().getColor(R.color.colorBody));
}
return true;
}
return false;
}
});
}
private void scrollResetListener(){
scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
resetAllButtons();
}
});
}
public void resetAllButtons(){
KapkanButton.setBackgroundColor(getResources().getColor(R.color.colorBody));
GlazButton.setBackgroundColor(getResources().getColor(R.color.colorBody));
FuzeButton.setBackgroundColor(getResources().getColor(R.color.colorBody));
TachankaButton.setBackgroundColor(getResources().getColor(R.color.colorBody));
}
}
fragment_operator_tab.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"
tools:context=".operatorTab">
<ScrollView
android:id="#+id/operatorScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorBody">
<RelativeLayout
android:id="#+id/kapkanButton"
android:layout_width="match_parent"
android:layout_height="60sp"
android:orientation="horizontal">
<ImageView
android:id="#+id/kapkanIcon"
android:layout_width="50sp"
android:layout_height="50sp"
android:layout_marginTop="5sp"
android:layout_marginLeft="10sp"
android:src="#drawable/ic_kapkan"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/kapkanIcon"
android:layout_marginLeft="10sp"
android:layout_marginTop="15sp"
android:layout_gravity="center"
android:fontFamily="#font/avenir"
android:text="Kapkan"
android:textColor="#ffffff"
android:textSize="25dp" />
<ImageView
android:layout_width="40sp"
android:layout_height="40sp"
android:layout_alignParentEnd="true"
android:layout_marginTop="10sp"
android:layout_marginEnd="10dp"
android:src="#drawable/ic_arrow_right" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/glazButton"
android:layout_below="#+id/kapkanButton"
android:layout_width="match_parent"
android:layout_height="60sp"
android:orientation="horizontal">
<ImageView
android:id="#+id/glazIcon"
android:layout_width="50sp"
android:layout_height="50sp"
android:layout_marginTop="5sp"
android:layout_marginLeft="10sp"
android:src="#drawable/ic_glaz"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/glazIcon"
android:layout_marginLeft="10sp"
android:layout_marginTop="15sp"
android:layout_gravity="center"
android:fontFamily="#font/avenir"
android:text="Glaz"
android:textColor="#ffffff"
android:textSize="25dp" />
<ImageView
android:layout_width="40sp"
android:layout_height="40sp"
android:layout_alignParentEnd="true"
android:layout_marginTop="10sp"
android:layout_marginEnd="10dp"
android:src="#drawable/ic_arrow_right" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/fuzeButton"
android:layout_below="#+id/glazButton"
android:layout_width="match_parent"
android:layout_height="60sp"
android:orientation="horizontal">
<ImageView
android:id="#+id/fuzeIcon"
android:layout_width="50sp"
android:layout_height="50sp"
android:layout_marginTop="5sp"
android:layout_marginLeft="10sp"
android:src="#drawable/ic_fuze"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/fuzeIcon"
android:layout_marginLeft="10sp"
android:layout_marginTop="15sp"
android:layout_gravity="center"
android:fontFamily="#font/avenir"
android:text="Fuze"
android:textColor="#ffffff"
android:textSize="25dp" />
<ImageView
android:layout_width="40sp"
android:layout_height="40sp"
android:layout_alignParentEnd="true"
android:layout_marginTop="10sp"
android:layout_marginEnd="10dp"
android:src="#drawable/ic_arrow_right" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/tachankaButton"
android:layout_below="#+id/fuzeButton"
android:layout_width="match_parent"
android:layout_height="60sp"
android:orientation="horizontal">
<ImageView
android:id="#+id/tachankaIcon"
android:layout_width="50sp"
android:layout_height="50sp"
android:layout_marginTop="5sp"
android:layout_marginLeft="10sp"
android:src="#drawable/ic_tachanka"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/tachankaIcon"
android:layout_marginLeft="10sp"
android:layout_marginTop="15sp"
android:layout_gravity="center"
android:fontFamily="#font/avenir"
android:text="Tachanka"
android:textColor="#ffffff"
android:textSize="25dp" />
<ImageView
android:layout_width="40sp"
android:layout_height="40sp"
android:layout_alignParentEnd="true"
android:layout_marginTop="10sp"
android:layout_marginEnd="10dp"
android:src="#drawable/ic_arrow_right" />
</RelativeLayout>
</RelativeLayout>
</ScrollView>
</FrameLayout>
Try to remove the ViewTreeObserver.OnScrollChangedListener when the fragment is destroyed this will avoid any listener that can be attached to a destroyed fragment context not to be triggered whenever you leave and come back to this fragment.
First: make a global field for the listener
public class operatorTab extends Fragment {
...
ViewTreeObserver.OnScrollChangedListener mScrollListener = new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
resetAllButtons();
}
};
Then set the listener wit the created field
private void scrollResetListener(){
scrollView.getViewTreeObserver().addOnScrollChangedListener(mScrollListener);
}
Then remove the listener.. I believe it's typically should be in onDestroyView() >> but also try it in onStop() or onPause if it didn't work
This also will solve memory leak of this listener whenever its callback is triggered after the Fragment's view is destroyed
#Override
public void onDestroyView() {
super.onDestroyView();
scrollView.getViewTreeObserver().removeOnScrollChangedListener(mScrollListener);
}
UPDATE
onStop()/onPause() worked for me
The reason that it didn't work with onDestroyView() because the OperatorTab fragment is a part of one of the ViewPager pages; and by default ViewPager loads a number of close pages in the background to be ready for the next page scroll; loading this pages include some of the fragment lifecycle callbacks like onCreateView, onStart, but not onResume.
When you leave the OperatorTab by scrolling the ViewPager to the next tab/page; onDestroyView() won't be created if the ViewPager decides that OperatorTab is a part of the cached/close pages that the user might return back to it later; and therefore the listener still there and after a few swipes of the pager, the OperatorTab fragment can be detached from the context leaving the listener there with memory leaks...
So, the best way in ViewPager fragment (or any View that loads its fragments in advance) is to stop any listeners once you leave the page, i.e. in onPause or onStop callbacks and not waiting until they are destroyed.
A possible reason for this error is that you are calling getResources() NOT in an Activity without using a context. So, you need to use context.getResources() instead where context may be one of these here . In you instance, I think getContext() will work.
So, I think you should search for all the times you are calling getResources and see if you are using a context or not.
The explanation for this error in a simple way is that you are trying to access the context required in getResources() before the fragment is instantiated.
Related
I have a a persistent bottom sheet behavior in my main activity. The bottom sheet has a container for a fragment with a ViewPager2. The problem is that the ViewPager2 prevents the bottom sheet from vertically scrolling.
I recreated the issue in the a sample app. As you can see from this gif right here, the vertical scrolling doesn't work if it's inside the ViewPager2. Only when I drag all the way down outside the ViewPager2, does it start ducking the bottom sheet. This makes scrolling awkward.
I tried the solution described here but it didn't change anything. The activity's root view is a CoordinatorLayout and the fragment's root view is a LinearLayout with a ConstraintLayout around the ViewPager2.
Here's the main activity layout:
<?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=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center">
<Button
android:id="#+id/expand_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Expand Bottom Sheet" />
</LinearLayout>
<FrameLayout
android:id="#+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true" />
</FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Here's the fragment inside the bottom sheet's layout:
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/purple_500">
<TextView
android:id="#+id/sheet_textview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:gravity="center_horizontal"
android:text="This is the sheet fragment"
android:textSize="24sp"
android:textAlignment="center"
android:textColor="#color/white" />
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="325dp"
android:layout_marginTop="75dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_horizontal"
android:text="Outside viewpager"
android:textSize="24sp"
android:textAlignment="center"
android:textColor="#color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#id/view_pager"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
Here's the MainActivity:
package com.example.myapplication;
import android.os.Bundle;
import android.widget.Button;
import android.widget.FrameLayout;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomSheetBehavior<FrameLayout> bottomSheetBehavior = BottomSheetBehavior.from(findViewById(R.id.bottom_sheet));
bottomSheetBehavior.setPeekHeight(200);
bottomSheetBehavior.setHideable(true);
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
Button expandButton = findViewById(R.id.expand_button);
expandButton.setOnClickListener(view -> bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED));
Fragment sheetFragment = new SheetFragment();
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, sheetFragment).commit();
}
}
And here's the SheetFragment:
package com.example.myapplication;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
public class SheetFragment extends Fragment {
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View contentView = inflater.inflate(R.layout.fragment_sheet, container, false);
ViewPager2 viewPager = contentView.findViewById(R.id.view_pager);
ViewPagerAdapter adapter = new ViewPagerAdapter();
viewPager.setAdapter(adapter);
return contentView;
}
public class ViewPagerAdapter extends RecyclerView.Adapter<ViewPagerHolder> {
#NonNull
#Override
public ViewPagerHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = getLayoutInflater().inflate(R.layout.pager_item, parent, false);
return new ViewPagerHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull ViewPagerHolder holder, int position) {
holder.bind(position);
}
#Override
public int getItemCount() {
return 5;
}
}
private class ViewPagerHolder extends RecyclerView.ViewHolder {
public ViewPagerHolder(#NonNull View itemView) {
super(itemView);
}
public void bind(int number) {
TextView textView = itemView.findViewById(R.id.pager_textview);
textView.setText(String.format("Inside ViewPager\nPage #%d", number));
}
}
}
Thanks to the great bobekos for helping me with this. His answer was:
Thats because the bottomsheet allow only one scrollable view. So to make it work you must disable the nestedscrolling of the viewpager. The problem is you must
get access to the recylerview inside the viewpager2 there is currently
no get method and the class is final so you can't use inheritance. But
you can do this:
//as extension function
fun ViewPager2.disableNestedScrolling() {
(getChildAt(0) as? RecyclerView)?.apply {
isNestedScrollingEnabled = false
overScrollMode = View.OVER_SCROLL_NEVER
}
}
ps.not tested directly
I translated it to Java:
RecyclerView innerRecyclerView = (RecyclerView) viewPager2.getChildAt(0);
if (innerRecyclerView != null) {
innerRecyclerView.setNestedScrollingEnabled(false);
innerRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
}
Tested and works perfectly.
My Main Activity. This is where all my code is.
package com.abhiandroid.tablayoutexample;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.VideoView;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.InterstitialAd;
import com.google.android.gms.ads.MobileAds;
public class MainActivity extends AppCompatActivity {
FrameLayout simpleFrameLayout;
TabLayout tabLayout;
ImageButton imageRopo;
Button btn_show;
InterstitialAd interstitialAd;
AdView adView1,adView2;
TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LayoutInflater layoutInflater= (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View firstfrag =getLayoutInflater().inflate(R.layout.fragment_first,null);
View thirdfrag =getLayoutInflater().inflate(R.layout.fragment_third,null);
btn_show = (Button)thirdfrag.findViewById(R.id.bt_show);
adView1= (AdView)thirdfrag.findViewById(R.id.ad_view);
adView2= (AdView)thirdfrag.findViewById(R.id.ad_view2);
imageRopo = (ImageButton)firstfrag.findViewById(R.id.buttonropo);
textView = (TextView)firstfrag.findViewById(R.id.testview);
imageRopo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.youtube.com"));
startActivity(intent);
textView.setText("The button works");
}
});
MobileAds.initialize(this, "ca-app-pub-8708219564656739~8048449285");
AdRequest adRequest = new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
.addTestDevice("355696115338836").build();
adView1.loadAd(adRequest);
adView2.loadAd(adRequest);
interstitialAd = new InterstitialAd(this);
interstitialAd.setAdUnitId("ca-app-pub-8708219564656739/2401085524");
interstitialAd.loadAd(new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
.addTestDevice("355697115338836").build());
btn_show.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
interstitialAd.show();
}
});
// get the reference of FrameLayout and TabLayout
simpleFrameLayout = (FrameLayout) findViewById(R.id.simpleFrameLayout);
tabLayout = (TabLayout) findViewById(R.id.simpleTabLayout);
// Create a new Tab named "First"
TabLayout.Tab firstTab = tabLayout.newTab();
firstTab.setText("Apps"); // set the Text for the first Tab
firstTab.setIcon(R.drawable.app); // set an icon for the
// first tab
tabLayout.addTab(firstTab); // add the tab at in the TabLayout
// Create a new Tab named "Second"
TabLayout.Tab secondTab = tabLayout.newTab();
secondTab.setText("Products"); // set the Text for the second Tab
secondTab.setIcon(R.drawable.company); // set an icon for the second tab
tabLayout.addTab(secondTab); // add the tab in the TabLayout
// Create a new Tab named "Third"
TabLayout.Tab thirdTab = tabLayout.newTab();
thirdTab.setText("Donate"); // set the Text for the first Tab
thirdTab.setIcon(R.drawable.donation); // set an icon for the first tab
tabLayout.addTab(thirdTab); // add the tab at in the TabLayout
// perform setOnTabSelectedListener event on TabLayout
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
// get the current selected tab's position and replace the fragment accordingly
Fragment fragment = null;
switch (tab.getPosition()) {
case 0:
fragment = new FirstFragment();
break;
case 1:
fragment = new SecondFragment();
break;
case 2:
fragment = new ThirdFragment();
break;
}
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.simpleFrameLayout, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.commit();
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
}
My activit_main.xml
<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"
android:layout_gravity="center"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<android.support.design.widget.TabLayout
android:id="#+id/simpleTabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabBackground="#android:color/darker_gray"
app:tabIndicatorColor="#f00"
app:tabSelectedTextColor="#f00"
app:tabTextColor="#000" />
<FrameLayout
android:id="#+id/simpleFrameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#9C27B0">
</FrameLayout>
</LinearLayout>
The buttons and views are in different fragments hence me having to inflate the layouts they are in.
This is my firstfragment.xml. This is where one of my button and one of my TextView is.
<ScrollView 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="#ffeadb"
tools:context=".FirstFragment">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#f7c5a8"
android:orientation="vertical"
tools:context=".FirstFragment"
tools:layout_editor_absoluteY="1dp">
<TextView
android:id="#+id/textView23"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:fontFamily="#font/roboto_bold"
android:gravity="center"
android:text="Why Choose China when you have the option for Indian?"
android:textSize="37sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/imageView"
android:layout_width="106dp"
android:layout_height="109dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="208dp"
android:layout_marginEnd="281dp"
android:layout_marginRight="281dp"
android:src="#drawable/tiktokl"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView22"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginLeft="12dp"
android:layout_marginTop="148dp"
android:layout_marginEnd="35dp"
android:layout_marginRight="35dp"
android:gravity="center"
android:text="Why Choose Chinese when you can choose an Indian Alternative."
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.255"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/imageView3"
android:layout_width="114dp"
android:layout_height="114dp"
android:layout_marginStart="149dp"
android:layout_marginLeft="149dp"
android:layout_marginTop="192dp"
android:layout_marginEnd="148dp"
android:layout_marginRight="148dp"
android:src="#drawable/red_arrow"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="#+id/buttonropo"
android:layout_width="132dp"
android:layout_height="118dp"
android:layout_marginStart="281dp"
android:layout_marginLeft="281dp"
android:layout_marginTop="183dp"
android:layout_marginEnd="24dp"
android:layout_marginRight="24dp"
android:layout_marginBottom="5dp"
android:adjustViewBounds="true"
android:background="#android:color/transparent"
android:baselineAlignBottom="false"
android:cropToPadding="true"
android:src="#drawable/roposoapplog"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/testview"
android:layout_width="88dp"
android:layout_height="19dp"
android:layout_marginStart="168dp"
android:layout_marginLeft="168dp"
android:layout_marginTop="336dp"
android:layout_marginEnd="155dp"
android:layout_marginRight="155dp"
android:textSize="25sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</ScrollView>
My ThirdFragement Activity file is very empty.
package com.abhiandroid.tablayoutexample;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
public class FirstFragment extends Fragment {
public FirstFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_first, container, false);
}
}
Before inflating the layouts, I would get a null object error and after inflating them they no-longer seem to work. They don't do anything. As you can see in my MainActivity.java file I had made is so that when a user clicks a button it redirects them to a website. I even made a TextView that updates itself when the Button is clicked so that I know that the Button is working. I have spent days trying to fix this error and have made no progress. I suspect it is related to some code being wrong while making the fragments.
You should add the logic for your Fragment's views inside your Fragment class.
So, instead of doing the logic for the button in the Activity, do it under the Fragment onCreateView():
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_first, container, false);
imageRopo = (ImageButton) v.findViewById(R.id.buttonropo);
textView = (TextView) v.findViewById(R.id.testview);
imageRopo.setOnClickListener(new View.OnClickListener() { ...
// ... and so on
return v;
}
I recently learned about Fragments in Android and was building a notepad application to practice them.
Idea: The idea behind the app is simple. I press the button to add a new note. A CardView Viewgroup turns visible. The fragment will be housed within this CardView.
Problem: When I press the button to add a new note, the fragment does not pop up.
MainActivity.java
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import java.util.Objects;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private CardView fragmentCardView;
private Button newNoteButton;
private FragmentManager fragmentManager = getSupportFragmentManager();
private FragmentTransaction fragmentTransaction;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setActionBar();
newNoteButton = findViewById(R.id.new_note_button);
fragmentCardView = findViewById(R.id.fragment_cardView);
}
void setActionBar(){
Objects.requireNonNull(getSupportActionBar()).setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
getSupportActionBar().setDisplayShowCustomEnabled(true);
getSupportActionBar().setCustomView(R.layout.layout_custom_action_bar);
}
void showCreateNoteFragment(){
CreateNoteFragment createNoteFragment = CreateNoteFragment.newInstance();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_cardView, createNoteFragment);
fragmentTransaction.commit();
fragmentCardView.setVisibility(View.VISIBLE);
}
#Override
public void onClick(View v) {
if (v == newNoteButton)
showCreateNoteFragment();
}
}
activity_main.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"
android:background="#F2F2F2"
tools:context=".MainActivity">
<ListView
android:id="#+id/notes_listView"
android:layout_width="match_parent"
android:layout_height="667dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<Button
android:id="#+id/new_note_button"
android:layout_width="350dp"
android:layout_height="50dp"
android:layout_marginTop="27dp"
android:fontFamily="#font/nunito_bold"
android:text="#string/new_note_button_string"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/notes_listView"/>
<androidx.cardview.widget.CardView
android:id="#+id/fragment_cardView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="100dp"
android:layout_marginBottom="100dp"
android:layout_marginStart="25dp"
android:layout_marginEnd="25dp"
android:visibility="invisible"/>
</androidx.constraintlayout.widget.ConstraintLayout>
CreateNoteFragment.java
package com.example.notepadapplication;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
public class CreateNoteFragment extends Fragment implements View.OnClickListener {
private EditText inputEditText;
public CreateNoteFragment() {
// Required empty public constructor
}
static CreateNoteFragment newInstance(){
return new CreateNoteFragment();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_create_note, container, false);
inputEditText = rootView.findViewById(R.id.input_editText);
Button saveButton = rootView.findViewById(R.id.save_button);
saveButton.setOnClickListener(this);
return rootView;
}
#Override
public void onClick(View v) {
String saveButtonText = inputEditText.getText().toString();
}
}
fragment_create_note.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_marginTop="100dp"
android:layout_marginBottom="100dp"
android:layout_marginStart="25dp"
android:layout_marginEnd="25dp"
android:background="#F2F2F2"
tools:context=".CreateNoteFragment">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/header_textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:text="#string/display_fragment_header_string"
android:layout_marginTop="10dp"
android:textAlignment="center"
android:textSize="20sp"
android:fontFamily="#font/nunito_bold"/>
<View
android:id="#+id/divider_view"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="5dp"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:layout_below="#id/header_textView"
android:background="#000000" />
<EditText
android:id="#+id/input_editText"
android:layout_width="match_parent"
android:layout_height="475dp"
android:layout_below="#id/divider_view"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="20dp"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:padding="10dp"
android:inputType="textMultiLine"
android:gravity="top"
android:background="#FFFFFF"
tools:ignore="Autofill,LabelFor,TextFields" />
<Button
android:id="#+id/save_button"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:text="#string/save_button_string"
android:fontFamily="#font/nunito_bold"/>
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Could anyone check why the fragment isn't popping up? Thanks for the help, guys.
P.S.: I think that the application might become a little bloated because of all the ViewGroups that I'm using. If you guys have a better way to design this, by all means, I would love any input.
When I press the button to add a new note, the fragment does not pop up.
This is expected since your button doesn't know what to do when pressed.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setActionBar();
newNoteButton = findViewById(R.id.new_note_button);
// Button will call activity's onClick whenever it's clicked
newNoteButton.setOnClickListener(this);
fragmentCardView = findViewById(R.id.fragment_cardView);
}
This is my first attempt to develop an android application.
I have a MainActivity with ConstraintLayout that has BottomNavigationView. Whenever the first navigation item is selected, I want to display a list of category (displayed in a fragment), then whenever this category is selected, another list will be displayed for items related to that particular category (in another fragment).
I have read in (Android - fragment .replace() doesn't replace content - puts it on top) it states that "static fragments written in XML are unable to be replaced, it has to be in a fragment container", how does it look like?
I tried to create my fragment container, but there is something wrong when I try to get the ListView (grand child of the container)
categoriesListView = getView().findViewById(R.id.categoriesList);
returns null.
MainActivity
package com.alsowaygh.getitdone.view.main;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.widget.TextView;
import com.alsowaygh.getitdone.R;
import com.alsowaygh.getitdone.view.services.CategoriesListFragment;
import com.alsowaygh.getitdone.view.services.OnCategorySelectedListener;
import com.alsowaygh.getitdone.view.services.ServicesListFragment;
public class MainActivity extends AppCompatActivity implements OnCategorySelectedListener {
private static final String TAG = "MainActivity";
FragmentManager fragmentManager;
FragmentTransaction fragmentTransaction;
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_services:
// mTextMessage.setText(R.string.title_services);
CategoriesListFragment categoriesListFragment = new CategoriesListFragment();
fragmentTransaction.add(R.id.container, categoriesListFragment);
fragmentTransaction.commit();
return true;
case R.id.navigation_bookings:
// mTextMessage.setText(R.string.title_bookings);
return true;
case R.id.navigation_chats:
// mTextMessage.setText(R.string.title_chats);
return true;
case R.id.navigation_settings:
return true;
}
return false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
}
#Override
public void onCategorySelected(String category) {
Log.w(TAG, "Successfully created CategoryListFragment!");
}
}
activity_main layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.main.MainActivity">
<android.support.design.widget.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="0dp"
android:layout_marginStart="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/navigation" />
</android.support.constraint.ConstraintLayout>
Fragment
package com.alsowaygh.getitdone.view.services;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import com.alsowaygh.getitdone.R;
import com.alsowaygh.getitdone.view.main.MainActivity;
public class CategoriesListFragment extends Fragment {
private ListView categoriesListView;
OnCategorySelectedListener categoryListener;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
final Bundle savedInstanceState) {
//initializing root view first to refer to it
View rootView = inflater.inflate(R.layout.activity_main, container, false);
//initializing ListView
categoriesListView = getView().findViewById(R.id.categoriesList);
//categories list
final String[] categories = {"first category", "second category", "third category", "Fourth category"};
//initializing and adding categories strings to the addapter
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(this.getContext(),
R.layout.category_textview);
for (String c : categories) {
arrayAdapter.add(c);
}
categoriesListView.setAdapter(arrayAdapter);
//implement onListItemClick
categoriesListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//retrieve string from categories list at clicked position
categoryListener.onCategorySelected(categories[position]);
}
});
return rootView;
}
#Override //to fource container activity to implement the OnCategorySelectedListener
public void onAttach(Context context) {
super.onAttach(context);
try{
categoryListener = (OnCategorySelectedListener) context;
}catch(ClassCastException e){
throw new ClassCastException(context.toString() + "must implement OnCategorySelectedListener");
}
}
}
fragments container
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/categories_list_fragment"
android:name="com.alsowaygh.getitdone.view.services.CategoriesListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp">
<ListView
android:id="#+id/categoriesList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp" />
</fragment>
</FrameLayout>
Your help will be much appreciated.
You need to add the FrameLayout container within the layout file of the MainActivity(activity_main), onclick of the buttons in BottomNavigationView replace with the fragment. In this way you have a Activity and the fragments are shown within the activity, on click of each menu item you can invoke to replace it with the fragments.
This should resolve your problem.
You need to change the layout as below in activity_main.xml.
<android.support.constraint.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/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.main.MainActivity">
<FrameLayout
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="0dp"
android:layout_marginStart="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/navigation" />
</android.support.constraint.ConstraintLayout>
In the MainActivity code, you need to change as below:
case R.id.navigation_services:
// mTextMessage.setText(R.string.title_services);
CategoriesListFragment categoriesListFragment = new CategoriesListFragment();
fragmentTransaction.replace(R.id.frame, categoriesListFragment);
fragmentTransaction.commit();
return true;
In the fragment layout file change to LinearLayout:
<LinearLayout
android:id="#+id/categories_list_fragment"
android:name="com.alsowaygh.getitdone.view.services.CategoriesListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp">
<ListView
android:id="#+id/categoriesList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp" />
</LinearLayout>
EDIT
In the fragment code, change the layout to the name of the fragment layout file(R.layout.fragment_layout_name).
View rootView = inflater.inflate(R.layout.fragment_layout_name, container, false);
//initializing ListView
categoriesListView = rootView.findViewById(R.id.categoriesList);
I want to move the following welcome label and logout button to the tab_profile fragment, right now it's visible in all 4 tabs which i created after successful login
activity_main.xml
<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"
tools:context="${relativePackage}.${activityClass}">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="?attr/colorPrimary"
android:elevation="6dp"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"/>
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/toolbar"
android:background="?attr/colorPrimary"
android:elevation="6dp"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_below="#id/tab_layout"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:gravity="center"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/welcome"
android:textSize="20dp" />
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textColor="#color/lbl_name"
android:textSize="24dp" />
<TextView
android:id="#+id/email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="13dp" />
<Button
android:id="#+id/btnLogout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dip"
android:background="#color/btn_logut_bg"
android:text="#string/btn_logout"
android:textAllCaps="false"
android:textColor="#color/white"
android:textSize="15dp" />
</LinearLayout>
MainAtivity.java
package gira.cdap.com.giira;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.widget.Button;
import android.widget.TextView;
import gira.cdap.com.giira.activity.LoginActivity;
import gira.cdap.com.giira.helper.SQLiteHandler;
import gira.cdap.com.giira.helper.SessionManager;
public class MainActivity extends AppCompatActivity {
private TextView txtName;
private TextView txtEmail;
private Button btnLogout;
private SQLiteHandler db;
private SessionManager session;
private int[] tabIcons = {
R.drawable.home,
R.drawable.tour,
R.drawable.event,
R.drawable.profile
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtName = (TextView) findViewById(R.id.name);
txtEmail = (TextView) findViewById(R.id.email);
btnLogout = (Button) findViewById(R.id.btnLogout);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.addTab(tabLayout.newTab().setIcon(tabIcons[0]));
tabLayout.addTab(tabLayout.newTab().setIcon(tabIcons[1]));
tabLayout.addTab(tabLayout.newTab().setIcon(tabIcons[2]));
tabLayout.addTab(tabLayout.newTab().setIcon(tabIcons[3]));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
final PagerAdapter adapter = new PagerAdapter
(getSupportFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
/**
* Logging out the user. Will set isLoggedIn flag to false in shared
* preferences Clears the user data from sqlite users table
* */
private void logoutUser() {
session.setLogin(false);
db.deleteUsers();
// Launching the login activity
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}
}
tab_profile.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="tab_profile"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</RelativeLayout>
ProfileActivity.java
package gira.cdap.com.giira.activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import gira.cdap.com.giira.R;
public class ProfileActivity extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
return inflater.inflate(R.layout.tab_profile, container, false);
}
}
PagerAdapter.java
package gira.cdap.com.giira;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import gira.cdap.com.giira.activity.EventActivity;
import gira.cdap.com.giira.activity.HomeActivity;
import gira.cdap.com.giira.activity.ProfileActivity;
import gira.cdap.com.giira.activity.TourActivity;
/**
* Created by Muqshid on 5/10/2016.
*/
public class PagerAdapter extends FragmentStatePagerAdapter {
int mNumOfTabs;
public PagerAdapter(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
HomeActivity tab1 = new HomeActivity();
return tab1;
case 1:
TourActivity tab2 = new TourActivity();
return tab2;
case 2:
EventActivity tab3 = new EventActivity();
return tab3;
case 3:
ProfileActivity tab4 = new ProfileActivity();
return tab4;
default:
return null;
}
}
#Override
public int getCount() {
return mNumOfTabs;
}
}
From what i understand of your succinct problem, just cut/paste the following:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/welcome"
android:textSize="20dp" />
<Button
android:id="#+id/btnLogout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dip"
android:background="#color/btn_logut_bg"
android:text="#string/btn_logout"
android:textAllCaps="false"
android:textColor="#color/white"
android:textSize="15dp" />
In the tab_profile.xml, and you will be good! That's the file you have to work on to personalize your fragment.