List of components in my app is following :
TabLayout - Tab1, Tab2, Tab3.
Fragments for Tabs - Tab1.xml & class, Tab2.xml & class, Tab3.xml & class.
ViewPager to show Fragments on tabs.
So, when app starts as i debugged the startup process, it works like following :
it calls 'Tab1.class',
then it calls 'Tab2.class',
and when swipe from 'Tab1' to 'Tab2', it calls 'Tab3.class'.
and when swipe from 'Tab2' to 'Tab3', it calls nothing.
on reverse swiping :
when swipe from 'Tab3' to 'Tab2', it calls 'Tab1.class'.
then when swipe from 'Tab2' to 'Tab1', it calls nothing.
Questions :
So, why does it do that?
How can i call ONLY 'tab1.class' when app starts on 'tab1'?
How can i call ONLY 'tab2.class' when i swipe from 'tab1' to 'tab2'?
MainActivity.java
public class MainActivity extends AppCompatActivity {
private TabLayout tabLayout;
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.viewPager);
PagerAdapter pagerAdapter = new FixedTabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
tabLayout.setupWithViewPager(viewPager);
}
class FixedTabsPagerAdapter extends FragmentPagerAdapter {
public FixedTabsPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
switch (position)
{
case 0:
return new Tab1();
case 1:
return new Tab2();
case 2:
return new Tab3();
default:
return null;
}
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position)
{
case 0:
return getString(R.string.tab1);
case 1:
return getString(R.string.tab2);
case 2:
return getString(R.string.tab3);
default:
return null;
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
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="vwc.com.newconcept.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/main_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TabLayout
android:id="#+id/tabLayout"
app:tabMode="scrollable"
app:tabGravity="center"
android:layout_gravity="top"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.v4.view.ViewPager>
</android.support.design.widget.AppBarLayout>
</android.support.v4.widget.DrawerLayout>
Please Do Tell Solution For This Problem.
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.
Hope this helps.
ViewPager mViewpager = (ViewPager)findView....
mViewPager.setOffscreenPageLimit(3);
ViewPager is intented to work in that way to avoid lag in animations while switching from one fragment to other fragment, it will load atleast one extra fragment alongside your Visible Fragment by which it makes sure there is scope to swipe.
because, while swiping view pager has capability to show two fragments simultaneously hence loads the one extra always, without two pages view pager is useless.
For Refresh Fragment When Fragment Visible
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (getFragmentManager() != null) {
getFragmentManager()
.beginTransaction()
.detach(this)
.attach(this)
.commit();
}
}
Related
I'm trying to achieve a layout that shows a view pager when the device is shown on portrait and show two panes when device is on landscape.
So I made two different layout files, one with only a ViewPager, the other with a LinearLayout and the other with two FrameLayouts, I don't think it is necessary to show them here. There is also a boolean value hasTwoPanes for the two configurations.
#Inject FragmentOne fragmentOne;
#Inject FragmentTwo fragmentTwo;
#Override
protected void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.activity_main);
FragmentManager fm = getSupportFragmentManager();
boolean hasTwoPanes = getResources().getBoolean(R.bool.hasTwoPanes);
TabLayout tabLayout = findViewById(R.id.tab_layout);
ViewPager viewPager = findViewById(R.id.view_pager);
if (hasTwoPanes) {
tabLayout.setVisibility(View.GONE);
} else {
tabLayout.setVisibility(View.VISIBLE);
tabLayout.setupWithViewPager(viewPager);
viewPager.setAdapter(new MyPagerAdapter(fm));
}
FragmentOne frag1 = (FragmentOne) fm.findFragmentByTag(getFragmentName(0));
if (frag1 != null) fragmentOne = frag1;
FragmentTwo frag2 = (FragmentTwo) fm.findFragmentByTag(getFragmentName(1));
if (frag2 != null) fragmentTwo = frag2;
if (hasTwoPanes) {
if (frag1 != null) {
fm.beginTransaction().remove(fragmentOne).commit();
fm.beginTransaction().remove(fragmentTwo).commit();
fm.executePendingTransactions();
}
fm.beginTransaction().add(R.id.frame_frag1, fragmentOne, getFragmentName(0)).commit();
fm.beginTransaction().add(R.id.frame_frag2, fragmentTwo, getFragmentName(1)).commit();
}
}
private class MyPagerAdapter extends FragmentPagerAdapter {
MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
if (position == 0) {
return fragmentOne;
} else {
return fragmentTwo;
}
}
#Override
public int getCount() {
return 2;
}
}
private static String getFragmentName(int pos) {
return "android:switcher:" + R.id.view_pager + ":" + pos;
}
Two fragments are injected with Dagger. If no fragments were already present, these injected fragments are added to the view pager or the layout depending on the orientation.
Because the view pager adapter gives a name to its fragments, I need to know that name (hence getFragmentName(int pos) method) to get back that fragment after rotation.
The result is state is correctly restored when rotating from portrait to landscape, but when rotating from landscape the portrait, the view pager is completely empty. When I rotate back to landscape, the fragments reappear. The tab layout is also buggy, there is no swipe animation, I can just continuously slide from one tab to the other, stopping anywhere.
To clarify things, this is happening in an Activity, there is no parent fragment. Even though the fragments are not shown, the fragment's onViewCreated is called. The view pager seems to correctly restore the fragment references in instantiateItem. Also, when debugging, fragments have the added to true and hidden to false. This make it seem like a view pager rendering issue.
How do I make the view pager show my fragments?
Is there a better way to achieve the behavior I want?
Have you tried using PagerAdapter instead of FragmentPagerAdapter? You will get better control over creation and handling of fragments. Otherwise you dont know what is the FragmentPagerAdapter doing (hes doing it for you, but probably wrong).
You cam move much of that logic into that class making the activity cleaner, and probably also fix the problems you have.
EDIT: Since we are talking orientation changes here, you should probably incorporate onConfigurationChanged callback to handle that logic better.
The solution I found is very simple, override getPageWidth in my pager adapter like this:
#Override
public float getPageWidth(int position) {
boolean hasTwoPanes = getResources().getBoolean(R.bool.hasTwoPanes);
return hasTwoPanes ? 0.5f : 1.0f;
}
R.bool.hasTwoPanes being a boolean resources available in default configuration and values-land. My layout is the same for both configuration, and the tab layout is simply hidden on landscape.
The fragment restoration is done automatically by the view pager.
Try this
Portrait Xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="#+id/tab"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Landscape Xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<FrameLayout
android:id="#+id/fragmentA"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<FrameLayout
android:id="#+id/fragmentB"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
Activity Java:
package com.dev4solutions.myapplication;
import android.graphics.Point;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import com.dev4solutions.myapplication.fragment.FragmentA;
import com.dev4solutions.myapplication.fragment.FragmentB;
public class FragmentActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Point point = new Point();
getWindowManager().getDefaultDisplay().getSize(point);
setContentView(R.layout.activity_frag);
if (point.y > point.x) {
TabLayout tabLayout = findViewById(R.id.tab);
ViewPager viewPager = findViewById(R.id.pager);
tabLayout.setupWithViewPager(viewPager);
viewPager.setAdapter(new PagerAdapter(getSupportFragmentManager()));
} else {
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragmentA, new FragmentA())
.commit();
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragmentB, new FragmentB())
.commit();
}
}
}
I have an activity in which I want to show a dialog with 2 tabs. I have the following code on button click which will show the dialog:
Dialog dialog = new Dialog(this);
// select_category is having ViewPager and TabLayout inside of a Framelayout
dialog.setContentView(R.layout.select_category);
ViewPager objViewPager = (ViewPager) dialog.findViewById(R.id.viewPager);
objViewPager.setAdapter(new MyTabsAdapter(getSupportFragmentManager()));
TabLayout mTabLayout = (TabLayout) dialog.findViewById(R.id.tabLayout);
mTabLayout.setTabTextColors(getResources().getColorStateList(R.color.tabcolors));
mTabLayout.setupWithViewPager(objViewPager);
dialog.show();
Adaper for ViewPager is as,
public class MyTabsAdapter extends FragmentPagerAdapter {
String[] tabs = {"FIRST", "SECOND"};
public MyTabsAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: {
// for now, returning plain fragment for simplicity
return new Fragment();
}
case 1: {
return new Fragment();
}
default:
return null;
}
}
}
select_category.xml is,
<FrameLayout 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/background"
android:theme="#style/NoActionBarTheme">
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/view_pager_top_margin"/>
<android.support.design.widget.TabLayout
android:id="#+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/primary" />
</FrameLayout>
When I run this code I'm getting IllegalArgumentException as,
java.lang.IllegalArgumentException: No view found for id 0x7f0a00da
(com.myapp:id/viewPager) for fragment Fragment
The TabLayout I'm using is from Google's design support library (android.support.design.widget.TabLayout).
I have no idea where I'm getting wrong. Please help!
Any tutorial / guide suggestion would be appreciated.
I read the documentation on FragmentPagerAdapter # FragmentPagerAdapter. In the webpage, the getItem() is coded differently than your code. Their suggestion is:
#Override
public Fragment getItem(int position) {
return ArrayListFragment.newInstance(position);
}
Notes:
You also have to define the static method newInstance.
I think you have to extend (subclass) a Fragment. In the above webpage, it subclass ListFragment.
I'm using ViewPager with PagerTabStrip in fragment A and everything works fine. Items are populated. ...Until I replace A with B and then replace again B with A.
fragment xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v4.view.PagerTabStrip
android:id="#+id/pager_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#222222"
android:textColor="#color/blue" />
</android.support.v4.view.ViewPager>
Debuggin shows that after second replacement getItem(int position) is never reached in FragmentPagerAdapter. Tabs are empty.
Adapter for tabs:
private class ChannelsFragmentPagerAdapter extends FragmentPagerAdapter {
final int PAGE_COUNT = dataChannelsList.size();
public ChannelsFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return PAGE_COUNT;
}
#Override
public CharSequence getPageTitle(int position) {
return dataChannelsList.get(position).getLang();
}
#Override
public Fragment getItem(int position) {
//This switch isnt reached for second replacement. Dunno why
switch (position){
case 0:
return FragmentChannelsUkr.newInstance();
case 1:
return FragmentChannelsRus.newInstance();
case 2:
return FragmentChannelsPol.newInstance();
default:
return null;
}
}
}
}
But again if I rotate the phone when tabs are empty they suddenly recreated in normal usual way.
the adapter call in onCreateView():
View rootView = inflater.inflate(R.layout.fragment_channels,container, false);
ViewPager viewPager = (ViewPager) rootView.findViewById(R.id.pager);
viewPager.setAdapter(new ChannelsFragmentPagerAdapter(getFragmentManager()));
Any ideas what invokes such behaviour? Appreciate any help with explanation.
Tell if some more code needed
You might be running out of memory or it would turn out to be a huge process reloading your fragments again. Try using FragmentStatePagerAdapter instead of FragmentPagerAdapter.
I'm new to Android, there's so much unknown that I don't even know which direction to look for solutions.. I hope experienced developers can enlighten me on this..
I have a UI design that is quite different from common Android app layout, most of which I've seen so far use Tabs or the upper-left corner control button..
My Main Activity is 1) full-screen without ActionBar 2) has a fixed "control panel" layer occupying the bottom half of the screen 3) a full-screen ViewPager (contains three pages, can swipe left and right) below the "control panel" layer.
I'm able to achieve either 1&2 or 1&3 but not all together. I think the main problem is to add the control panel on top of the ViewPager within the same screen.
I tried to put ViewPager and "control panel" as two fragments inside the MainActivity layout.. it didn't work... below is the layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.MainActivity">
<fragment
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:layout="#layout/fragment_pager"/>
<fragment android:name="com.example.MainFragment"
android:layout_width="fill_parent"
android:layout_height="200dip"
android:layout_gravity="bottom"
tools:layout="#layout/fragment_main"/>
</LinearLayout>
In case you need more info, attach my MainActivity as well
public class MainActivity extends FragmentActivity {
static final int NUM_ITEMS = 3;
private FragmentPagerAdapter mAdapter;
private ViewPager mPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar actionBar = getActionBar();
actionBar.hide();
setContentView(R.layout.activity_main);
mAdapter = new DashboardAdapter(getSupportFragmentManager());
mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mPager.setCurrentItem(1);
}
public static class DashboardAdapter extends FragmentPagerAdapter {
public DashboardAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new FirstFragment();
case 1:
return new SecondFragment();
case 2:
return new ThirdFragment();
default:
return null;
}
}
}
}
I got Error inflating class fragment, so probably happens when I create the fragment
inflater.inflate(R.layout.first_fragment, container, false);
Because "control panel" is outside the ViewPager, thus the view cannot be inflated... Then what's the correct way of doing it?
Use a RelativeLayout as the root of your MainActivity.
The ViewPager should be the first child with match_parent.
Your control panel can be aligned at the bottom using layout_alignParentBottom="true". This will also make it on top of the ViewPager.
I am trying to make some kind of transition on Fragments, and i am using default application skeleton in eclipse for creating FragmentActivity. I noticed other posts for specifying custom transition animation from xml, but it is being done on Transaction, and none is using FragmentActivity. (Which is btw much easier.)
I would like to know how to make custom transitions in FragmentActivity.
Thanks in advance!
EDIT: Somthing like this but for FragmentActivity.
MusicPlayerActivity.java
public class MusicPlayerActivity extends FragmentActivity {
SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// init pager and set its adapter
mSectionsPagerAdapter = new SectionsPagerAdapter(
getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
//other init code ...
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new MainFragment();
case 1:
return new AllSongsFragment();
case 2:
return new SettingsFragment();
default:
return null;
}
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
/**
* Get title for supplied Fragment number.
*/
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section1).toUpperCase(l);
case 1:
return getString(R.string.title_section2).toUpperCase(l);
case 2:
return getString(R.string.title_section3).toUpperCase(l);
}
return null;
}
}
//other methods
}
activity_music_player.xml
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MusicPlayerActivity$OptionsFragment" >
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MusicPlayerActivity" >
<android.support.v4.view.PagerTitleStrip
android:id="#+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#33b5e5"
android:paddingBottom="4dp"
android:paddingTop="4dp"
android:textColor="#fff" />
</android.support.v4.view.ViewPager>
<ListView
android:id="#+id/drawer"
android:layout_width="160dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#333333"
android:choiceMode="singleChoice" />
As you said in your comment, you're using a ViewPager. This is slightly different to performing an animation on a FragmentTransaction.
What you'll want to use is a ViewPager.PageTransformer. There are some details on how to do that here
Question is not much clear to me. But i believe this may serve your purpose.
from: http://developer.android.com/reference/android/app/Activity.html#overridePendingTransition(int, int)
public void overridePendingTransition (int enterAnim, int exitAnim)
Added in API level 5
Call immediately after one of the flavors of startActivity(Intent) or finish() to specify an explicit transition animation to perform next.
As of JELLY_BEAN an alternative to using this with starting activities is to supply the desired animation information through a ActivityOptions bundle to {#link #startActivity(Intent, Bundle) or a related function. This allows you to specify a custom animation even when starting an activity from outside the context of the current top activity.
Parameters
enterAnim A resource ID of the animation resource to use for the incoming activity. Use 0 for no animation.
exitAnim A resource ID of the animation resource to use for the outgoing activity. Use 0 for no animation.