I have a FragmentActivity which hosts a FragmentTabHost.
The goal is to have swipeable content in the first tab.
So the first tab hosts a FragmentPagerAdapter and ViewPager.
The app compiles fine but nothing is shown in the first tab and it is not swipeable.
I'm still new to android and I'm stuck. I hope that someone can help me.
Here is my relevant code:
MainActivity:
public class MainActivity extends FragmentActivity implements OnTabChangeListener
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initTabs();
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private void initTabs()
{
FragmentTabHost tabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
tabHost.setup(this, getSupportFragmentManager(),R.id.realtabcontent);
tabHost.addTab(tabHost.newTabSpec("Übersicht").setIndicator("Übersicht"), OverviewFragment.class, null); // <- shall contain swipeable content
tabHost.addTab(tabHost.newTabSpec("Einstellungen").setIndicator("Einstellungen"), SettingsFragment.class, null); // <- 'static' content
tabHost.setOnTabChangedListener(this);
}
...
}
OverviewFragment (shall host the swipeable content):
public class OverviewFragment extends Fragment
{
ViewPager _pagerView;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
_pagerView = (ViewPager)inflater.inflate(R.layout.tab_overview, container, false).findViewById(R.id.viewpager);
initPager();
return inflater.inflate(R.layout.tab_overview, container, false);
}
private void initPager()
{
FragmentManager fm = getChildFragmentManager();
PageAdapter pageAdapter = new PageAdapter(fm);
_pagerView.setAdapter(pageAdapter);
}
}
PageAdapter:
public class PageAdapter extends FragmentPagerAdapter
{
public PageAdapter(FragmentManager fm)
{
super(fm);
}
#Override
public Fragment getItem(int arg0)
{
MemoryFragment m1 = new MemoryFragment();
return m1;
}
#Override
public int getCount()
{
return 5;
}
}
MemmoryFragment (the fragment that should be shown as a page in the FragmentPagerController):
public class MemoryFragment extends Fragment
{
#Override
public void onCreate(Bundle savedInstanceState) {
}
#Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.memmory, container,false);
TextView tv = (TextView ) v.findViewById(R.id.textViewTest);
tv.setText("You are viewing the page Swipe Horizontally left / right");
return v;
}
}
I know that this code shows nothing meaningful. It should just show 5 swipeable pages with the same text for the start.
Related
I have created an experimental app in which I'm trying to learn to establish a successful communication b/w two fragments.
What I have is just one activity which is Main Activity. In this activity I have a view pager element in XML. I've created custom pager adapter which extends to Fragment Pager Adapter and two Fragments which are children and supplied by my pager adapter to the view pager.
What I'm trying to do is: FirstFragment has one button which on clicked changes the background color of the SecondFragment(there's a relative layout as parent), which will be visible on one swipe.
What I've done so far: I created an interface in FirstFragment, implemented in MainActivity, created a method in SecondFragment which changes the background color of layout and finally getting the SecondFragment in MainActivvity (at least trying to) and calling its method. But app is crashing on button click saying "Fragment SecondFragment not attached to a context"
Here's the code:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
tools:context=".MainActivity">
<android.support.v4.view.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.constraint.ConstraintLayout>
MainActivity.java
package com.example.android.laboratory;
import...
public class MainActivity extends AppCompatActivity implements FirstFragment.MyListener {
ViewPager viewPager;
MyPagerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = findViewById(R.id.view_pager);
adapter = new MyPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
}
#Override
public void changeColor() {
SecondFragment secondFragment = new SecondFragment();
secondFragment.changeColor();
}
}
Custom Adapter:
package com.example.android.laboratory;
import ...
public class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
switch (i) {
case 0:
return new FirstFragment();
case 1:
return new SecondFragment();
}
return null;
}
#Override
public int getCount() {
return 2;
}
}
First Fragment:
package com.example.android.laboratory;
import ...
public class FirstFragment extends Fragment {
MyListener listener;
public FirstFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_first, container, false);
Button button = view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listener.changeColor();
}
});
return view;
}
public interface MyListener{
void changeColor();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
listener = (MyListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(getActivity().toString() + " must implement MyListener interface.");
}
}
}
Second Fragment:
package com.example.android.laboratory;
import ...
public class SecondFragment extends Fragment {
RelativeLayout relativeLayout;
public SecondFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_second, container, false);
relativeLayout = view.findViewById(R.id.layout);
return view;
}
public void changeColor() {
relativeLayout.setBackgroundColor(getResources().getColor(R.color.colorAccent));
}
}
Crash log:
12-23 12:18:03.574 31428-31428/com.example.android.laboratory E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.laboratory, PID: 31428
java.lang.IllegalStateException: Fragment SecondFragment{2bfa6ff2} not attached to a context.
at android.support.v4.app.Fragment.requireContext(Fragment.java:696)
at android.support.v4.app.Fragment.getResources(Fragment.java:760)
at com.example.android.laboratory.SecondFragment.changeColor(SecondFragment.java:32)
at com.example.android.laboratory.MainActivity.changeColor(MainActivity.java:28)
at com.example.android.laboratory.FirstFragment$1.onClick(FirstFragment.java:31)
at android.view.View.performClick(View.java:4791)
at android.view.View$PerformClick.run(View.java:19903)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5296)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:707)
You can see this doc https://developer.android.com/training/basics/fragments/communicating
If you want to make you own bicycle for some reasons, you could try something like this (observer pattern)
MyModel
import java.util.ArrayList;
public class MyModel {
private int color = R.color.colorPrimary;
private ArrayList<MyObserver> observers = new ArrayList<>();
interface MyObserver {
void setColor(int color);
}
public void setColor(int color) {
this.color = color;
for (int i = 0; i < observers.size(); i++) {
observers.get(i).setColor(color);
}
}
public void addObserver(MyObserver newObserver) {
if (observers.indexOf(newObserver) < 0) {
observers.add(newObserver);
}
}
public void deleteObserver(MyObserver oldObserver) {
if (observers.indexOf(oldObserver) > -1) {
observers.remove(oldObserver);
}
}
}
FirstFragment
public class FirstFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_first, container, false);
Button button = view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
MainActivity mainActivity = (MainActivity) getActivity();
mainActivity.myModel.setColor(R.color.colorAccent);
}
});
return view;
}
}
SecondFragment
public class SecondFragment extends Fragment implements MyModel.MyObserver {
RelativeLayout relativeLayout;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_second, container, false);
relativeLayout = view.findViewById(R.id.layout);
MainActivity mainActivity = (MainActivity) getActivity();
mainActivity.myModel.addObserver(this);
return view;
}
#Override
public void onDestroy() {
MainActivity mainActivity = (MainActivity) getActivity();
mainActivity.myModel.deleteObserver(this);
super.onDestroy();
}
#Override
public void setColor(int color) {
relativeLayout.setBackgroundColor(getResources().getColor(color, null));
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
ViewPager viewPager;
MyPagerAdapter adapter;
public MyModel myModel = new MyModel();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = findViewById(R.id.view_pager);
adapter = new MyPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
}
}
Below is my Code.
Using ViewPager I have made 2 XML file for two Pages and their Class file.
Now I need if I click on First Screen of ViewPager, a new activity should launch.
I got 2 pages, so If I Click First Screen, A.class intent Called. If I click on Second Screen, B.class intent should be Called.
Codes:-
MainActvity:
public class MainActivity extends ActionBarActivity {
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.pager);
/** set the adapter for ViewPager */
mViewPager.setAdapter(new SamplePagerAdapter(
getSupportFragmentManager()));
}
/** Defining a FragmentPagerAdapter class for controlling the fragments to
be shown when user swipes on the screen. */
public class SamplePagerAdapter extends FragmentPagerAdapter {
public SamplePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
/** Show a Fragment based on the position of the current screen */
if (position == 0) {
return new SampleFragment();
} else
return new SampleFragmentTwo();
}
#Override
public int getCount() {
// Show 2 total pages.
return 2;
}
}
}
SampleFragment.java
public class SampleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_one, null);
return rootView;
}
}
SampleFragmentTwo.java
public class SampleFragmentTwo extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_two, container,
false);
return rootView;
}
}
CustomSwipeAdapter:
public class CustomSwipeAdapter extends PagerAdapter {
#Override
public int getCount() {
return 0;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return false;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
return super.instantiateItem(container, position);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
}
As mentioned in one of the comments, In your fragment classes A and B put onClick listener on views and launch intent from there like below:
public class SampleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_one, null);
rootView.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
// do something when the button is clicked
Intent activityA = new Intent(getActivity(),ActivityA.class);
startActivity(activityA);
}
return rootView;
}
}
similarlly goes for your second fragment.
I am creating swipe screens using ViewPager where i have two fragments to show using swipes inside FragmentActivity .Please consider the following code :
Fragment_One.java
public class Fragment_One extends Fragment {
private Button btnNext;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_one,null);
btnNext = (Button) v.findViewById(R.id.btnNext);
btnNext.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment fragment = new Fragment_Two();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragmentOne,fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
return v;
}
}
2.Fragment_Two.java
public class Fragment_Two extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_two,null);
}
}
3. PagerAdapter.java
public class PagerAdapter extends FragmentPagerAdapter {
List<Fragment> listFragments ;
public PagerAdapter(FragmentManager fm,List<Fragment> listFragments) {
super(fm);
this.listFragments = listFragments;
}
#Override
public Fragment getItem(int i) {
return listFragments.get(i);
}
#Override
public int getCount() {
return listFragments.size();
}
}
4.MainActivity.java
public class MainActivity extends FragmentActivity{
private List<Fragment> listFragments;
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.viewPager);
Fragment_One fragment_one = new Fragment_One();
Fragment_Two fragment_two = new Fragment_Two();
listFragments = new ArrayList<>();
listFragments.add(fragment_one);
listFragments.add(fragment_two);
PagerAdapter pagerAdapter = new PagerAdapter(getSupportFragmentManager(),listFragments);
viewPager.setAdapter(pagerAdapter);
}
}
The above mentioned code is working fine while swiping screens .But i click on next button ,fragment is replaced with another but is displayed on the same screen.I am not able to fix the issue.Screenshot is given below :
Next button should work in the same way as we swipe the screen .Please help me to fix the issue.
Wouldn't that be easier to use:
.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
viewPager .setCurrentItem(viewPage.getCurrentItem() + 1);
});
I have been looking and having a hard time finding a clear cut example? I am trying to understand how to create a viewpager within a fragment that is open as a drawer item from my mainActivity...
This is my attempt but I think I am doing something wrong whether it be that I am including it incorrectly or have it in the wrong spot...
public class RandomFragment extends android.app.Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_random, container, false);
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ViewPager mViewPager = (ViewPager) view.findViewById(R.id.random_pager);
mViewPager.setAdapter(new MyAdapter(getChildFragmentManager()));
}
public static class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return 4;
}
#Override
public Fragment getItem(int position) {
Bundle args = new Bundle();
args.putInt(TextViewFragment.POSITION_KEY, position);
return TextViewFragment.newInstance(args);
}
}
I use this one hope it help you too : https://github.com/thecodepath/android_guides/wiki/ViewPager-with-FragmentPagerAdapter
So you can use this one: https://github.com/astuetz/PagerSlidingTabStrip
I'm using PagerSlidingTabStrip library for ViewPager https://github.com/astuetz/PagerSlidingTabStrip. I want to change the fragments while scrolling. I achieved that with the below code.
MainActivity.java
public class MainActivity extends SherlockFragmentActivity {
private MyPagerAdapter adapter;
ViewPager pager;
private PagerSlidingTabStrip tabs;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
pager = (ViewPager) findViewById(R.id.pager);
adapter = new MyPagerAdapter(getSupportFragmentManager());
pager.setAdapter(adapter);
final int pageMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources()
.getDisplayMetrics());
pager.setPageMargin(pageMargin);
tabs.setViewPager(pager);
}
public class MyPagerAdapter extends FragmentPagerAdapter {
private final String[] TITLES = {"First","Second","Third"};
private SherlockFragment[] fragments = new SherlockFragment[] { new FirstFragment(), new SecondFragment(), new ThirdFragment()};
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
return TITLES[position];
}
#Override
public int getCount() {
return TITLES.length;
}
#Override
public Fragment getItem(int position) {
return fragments[position];
}
}
}
FirstFragment.java
public class FirstFragment extends SherlockFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.fragment_main, container, false);
Toast.makeText(getSherlockActivity(), "This is from first", Toast.LENGTH_SHORT).show();
return v;
}
}
SecondFragment.java
public class SecondFragment extends SherlockFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.fragment_main, container, false);
Toast.makeText(getSherlockActivity(), "SecondFragment", Toast.LENGTH_SHORT).show();
return v;
}
}
ThirdFragment.java
public class ThirdFragment extends SherlockFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.fragment_main, container, false);
Toast.makeText(getSherlockActivity(), "ThirdFragment", Toast.LENGTH_SHORT).show();
return v;
}
}
I got the three fragments and I'm testing them with Toasts.
When the application opens with the MainActivity, FirstFragment is attached to the Activity , but it shows two toasts, one from Firstragment and other from SecondFragment , and when I scroll to second tab, it shows the toast of ThirdFragment.
So, I figured its going like this. If I scroll from left to right , the fragment right to the current fragment is displayed and if I scroll from right to left, the fragment left to the current fragment is displayed. Please help.
Thanks.
It's because of fragments caching. When you visit some fragments, sibling fragments to it also being created (onCreate() called).