I use a PageViewer to scroll through two types of fragments.
One of them has an EditText the other multiple buttons.
Upon entering the EditText Fragment I automatically open the softkeyboard. Upon entering the Button Fragment i close it.
This works fine.
The problem is that I have multiple EditText Fragments as direct neighbours to each other.
-> I dont want the keyboard to be closed when transitioning from one EditText Fragment to the next.
For this I somehow need to predict the class to which I am transitioning next.
Is there a way to achieve this?
Note: I close the keyboard in the pageTransform method as soon as a swipe movement occurs.
EDIT
because of an request in the comments here my PagerAdapter:
public class ButtonCollectionPagerAdapter extends FragmentStatePagerAdapter {
public ButtonCollectionPagerAdapter(FragmentManager fm) {
super(fm);
}
private Fragment currentFragment;
#Override
public Fragment getItem(int i) {
Bundle args = new Bundle();
List<MultipleChoiceQuestion> multipleChoiceQuestions = QuestionTexts.getMCQuestionTexts();
List<String> questionTexts = QuestionTexts.getQuestionTexts();
if(i < multipleChoiceQuestions.size()){
String question = multipleChoiceQuestions.get(i).getText();
ArrayList<String> choices = (ArrayList<String>) multipleChoiceQuestions.get(i).getChoices();
currentFragment = ButtonFragment.newInstance(question, choices, i);
} else if(i < (multipleChoiceQuestions.size() + questionTexts.size())){
currentFragment = TextViewFragment.newInstance(questionTexts.get(i - multipleChoiceQuestions.size()), i);
} else {
currentFragment = SendFragment.newInstance(i);
}
return currentFragment;
}
#Override
public int getCount() {
return 23;
}
#Override
public CharSequence getPageTitle(int position) {
return "OBJECT " + (position + 1);
}
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object){
super.setPrimaryItem(container, position, object);
currentFragment = (Fragment) object;
((PagerAdapterUpdateProgress) object).onGettingPrimary(position);
}
public Fragment getCurrentFragment() {
return currentFragment;
}
}
I think the more simple way to do that is to open/close keyboard directly from your fragments. You can determine when your fragment becomes visible by overriding setUserVisibleHint method of your fragment. The code in this method for your EditText Fragment should just show keyboard, and the code for other fragment should hide keyboard.
This is an interesting question.
I believe that you can achieve what you are doing by using ViewPager.OnPageChangeListener listener especially onPageSelected(int position) method in which we could get the position of the currently selected fragment after the swipe animation has finished.
mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
Log.d("ViewPager", "Page selected " + position);
onPageSelectedLogic(position);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
// This is because the first fragment doesn't fire the OnPageChangeListener.
onPageSelectedLogic(0);
an this is the implementation of onPageSelectedLogic method
private void onPageSelectedLogic(int position) {
// Check the type of the fragment editable vs button
if(!mPagerAdpater.isFragmentEdiatable(position)) {
// Close the Keyboard
}
}
And this is how you should implement your PagerAdapter
class CustomPagerAdapter extends FragmentStatePagerAdapter {
private SparseBooleanArray fragmentsEditable = new SparseBooleanArray();
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment fargment;
// get the fragment
if(some condition) {
// Get an editable fragment
fragmentsEditable.put(position, true);
} else {
fragmentsEditable.put(position, false);
}
return fragment;
}
#Override
public int getCount() {
return NUM_PAGES;
}
public boolean isFragmentEditable(int postion) {
return fragmentsEditable.get(postion);
}
}
Related
I using view pager for swipe view for android app. I build view pager Dynamically. Like add and remove item. Now i want to know how to get exactly position of view pager items.For example, I have 3 items, i want to get 3rd number position when i am in 2nd or 1st item. i used viewPager.getCurrentItem() but it return where i am.
Please suggest me how to give personal ids of every viewpager items and used it in when item is background or on screen.Thanks please help me about this, i left 2 weeks already for this. Thanks in advance
public TabsPageAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
return new MyWebBrowser();
}
#Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
#Override
public int getCount() {
return COUNT_TAB;
}
}
Now this code Under my fragment class, from WebView chrom class i want to set up title as website title.
#Override
public void onReceivedTitle(WebView view, String title) {
TAB_TITLE=title;
Toast.makeText(HomeActivity.this,title,Toast.LENGTH_LONG).show();
super.onReceivedTitle(view, title);
}
take a look at this Adapter:
class MyAdapter extends FragmentStatePagerAdapter
{
private final SparseArray<WeakReference<YourFragment>> mPageReferences;
public MyAdapter(FragmentManager fm) {
super(fm);
mPageReferences = new SparseArray<WeakReference<YourFragment>>();
}
#Override
public Fragment getItem(int i) {
WeakReference<YourFragment> fragment =
new WeakReference<YourFragment>(YourFragment.newInstance());
mPageReferences.put(i, fragment);
return fragment.get();
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
mPageReferences.remove(position);
}
#Override
public int getCount() {
return number of fragment;
}
public YourFragment getFragment(int key) {
return mPageReferences.get(key).get();
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
WeakReference<YourFragment> fragment = new WeakReference<YourFragment>((YourFragment) super.instantiateItem(container,
position));
mPageReferences.put(position, fragment);
return fragment.get();
}
}
you can easily get the reference of any pages from mPageReferences BUT be careful because it may be null because it is possible that it has not created when you call it. you can use (getFragment(int key) to get the item at the position of key)
you can know the current position from the PagerAdapter.
by calling pageAdapter.getItemPosition(itemNumber)
link to the documentation
I created a viewpager and an adapter with fragments that contains 2 views. I want to make the second view in the fragment invisible when I click on the frist one. I implemented this method on my view to handle the click events
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
ImageFragment fragment = (ImageFragment) ImageGallery.fragmentmanager.findFragmentByTag("android:switcher:"+R.id.imagerpager+":"+position);
if (fragment != null) {
fragment.setTransparency();
}
return super.onSingleTapConfirmed(e);
}
All fragments I get are null. To make sure that my objects are not null, following works but for the wrong(preloaded) fragments
ImageFragment fragment = (ImageFragment) ImageGallery.fragmentmanager.findFragmentById(R.id.imagepager);
I`m quite sure I have to implement a FragmentTransition to my adapter to make fragmentmanager.findFragmentByTag work. But I could not figure out how to do that. My adapter looks like
public class GalleryAdapter extends FragmentStatePagerAdapter {
private int mCount = pictureUrlList.size();
public GalleryAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
ImageFragment fragment = ImageFragment.newInstance(position);
return fragment;
}
#Override
public int getCount() {
return mCount;
}
public void setCount(int count) {
if (count > 0 && count <= 10) {
mCount = count;
notifyDataSetChanged();
}
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
Can anybody show me how to do that?
I have a Fragment for a ViewPager. The ViewPager is updated based on an action fired by the user. Well when the Fragment is recreated so to speak, the page of a ViewPager is not updated as should be, or even shown for that matter! When I swipe over to other pages and then back to that one, it loads?
Here is the Fragment:
public static class CardFrontFragment extends Fragment {
public CardFrontFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = null;
rootView = inflater.inflate(R.layout.activity_dashboard, container, false);
TextView textviewLocation = (TextView)rootView.findViewById(R.id.textview_location);
TextView textviewConditions = (TextView)rootView.findViewById(R.id.textview_points);
ViewPager viewPagerDashboard = (ViewPager)rootView.findViewById(R.id.viewPager_Dashboard);
if(overviewData != null) {
textviewLocation.setText(overviewData.getLocation());
textviewPoints.setText(overviewData.getPoints());
viewPagerDashboard.setAdapter(adapterSectionsPager);
adapterSectionsPager.notifyDataSetChanged();
viewPagerDashboard.destroyDrawingCache();
textviewLocation.setText(overviewData.getWeathersLocation());
textviewPoints.setText(overviewData.getWeathersConditions());
}
return rootView;
}
}
Here is the adapter:
public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
return DashboardSectionFragment.create
(uiContext, position, overviewData, forecastData, hourlyData, radarData);
}
#Override
public int getCount() {
// Show 4 total pages:
return 4;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section_1).toUpperCase(l);
case 1:
return getString(R.string.title_section_2).toUpperCase(l);
case 2:
return getString(R.string.title_section_3).toUpperCase(l);
case 3:
// Radar Page:
return getString(R.string.title_section_4).toUpperCase(l);
}
return null;
}
}
I heard I am extending the correct one FragmentStatePagerAdapter over FragmentPagerAdapter. Yet nothing is working. I have called many methods of the ViewPager and adapter in the Fragment when the ViewPager is recreated but it still does not load initially till it appears off screen then back on...
Thanks!
try overriding the following like this and update the viewpager and pageradapater instance
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
viewPager.invalidate();
pagerAdapter.notifyDataSetChanged();
}
or else depending upon the specific location of the Fragment you can do the following
#Override
public void onPageSelected(int arg0) {
if(int == 2)// In which specifi fragment you want to update the view
{
viewPager.invalidate();
pagerAdapter.notifyDataSetChanged();
}
}
I hope this would help you
Try to update view when fragment get visible to user as follows:
public class MyFragment extends Fragment
#Override
public void setMenuVisibility(final boolean visible) {
super.setMenuVisibility(visible);
if (visible) {
**//Update views here**
}
}
I've looked at so many questions here that I don't even know exactly what I'm looking for.
I have a simple app that uses a ViewPager. It has 3 tabs and there is a fragment for each tab. The first fragment contains a ListView. I want to be able to click on an element in the ListView and have that bring me to a different fragment.
So basically I want to remove the fragment that contained the ListView once an element is clicked and add in a new fragment. I've tried to do this in a few different ways with none working.
The last thing I tried was to edit the TabsPageAdapter once an element was clicked which pretty much works except when I press the back button it exits the app. Also it doesn't seem like the cleanest way of doing this.
TabsPagerAdapter
public class TabsPagerAdapter extends FragmentStatePagerAdapter {
SherlockFragment mf;
TalkingPointsFragment tpf;
ContactFragment gf;
int mode = 0;
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
mf = new CanvassFragment();
tpf = new TalkingPointsFragment();
gf = new ContactFragment();
}
public TabsPagerAdapter(FragmentManager fm, int mode)
{
super(fm);
if(mode == 0)
{
mf = new CanvassFragment();
tpf = new TalkingPointsFragment();
gf = new ContactFragment();
}
else if(mode == 1)
{
mf = new ContactFragment();
tpf = new TalkingPointsFragment();
gf = new ContactFragment();
}
}
#Override
public SherlockFragment getItem(int index) {
switch (index) {
case 0:
return mf;
case 1:
return tpf;
case 2:
return gf;
}
return null;
}
#Override
public int getCount() {
// get item count - equal to number of tabs
return 3;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object)
{
}
}
The onclick code:
ViewPager viewp = (ViewPager) getActivity().findViewById(R.id.pager);
TabsPagerAdapter mAdapter = new TabsPagerAdapter(getActivity().getSupportFragmentManager(),1);
viewp.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
layout_main.xml
<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="0dp"
android:layout_weight="1"
android:actionBarTabStyle="#drawable/actionbar_tab_indicator">
I FragmentStatePagerAdapter too and when a user selects map from the ActionBar, I add the GoogleMapsFragment on top of the FragmentStatePagerAdapter:
// create a new map
mapsFragment = GoogleMapFragment.newInstance();
// Then we add it using a FragmentTransaction.
FragmentTransaction fragmentTransaction = getSupportFragmentManager()
.beginTransaction();
fragmentTransaction.add(android.R.id.content, mapsFragment,
FRAGMENT_MAP_TAG);
fragmentTransaction.commit();
For your case you would probably need to add it to the backstack too, which I have not because in my app the user has to navigate back using the ActionBar.
Thought this approach could work for you too when a user selects an item from your list.
Of course this has the disadvantage of not being able to use the FragmentStatePagerAdapter until the user navigates back. So I am not sure wether that would be acceptable for your app.
Ok, so this took a bit more code that I imagined. Hope you get the idea:
public class MainClass extends FragmentActivity implements CanvassCallback {
// save a single reference to ViewPager and TabsPagerAdapter
private ViewPager mViewPager;
private TabsPagerAdapter mAdapter;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.mViewPager = (ViewPager) findViewById(R.id.pager);
this.mAdapter = new TabsPagerAdapter(getSupportFragmentManager(), this);
mViewPager.setAdapter(mAdapter);
...
}
// from the CanvassCallback interface
public void itemSelected() {
mAdapter.canvassSelected();
mAdapter.notifyDataSetChanged();
}
#Override
public void onBackPressed() {
if (mViewPager.getCurrentItem() == 0 && mAdapter.isCanvassSelected() {
mAdapter.canvassSelected();
mAdapter.notifyDataSetChanged();
}
else {
super.onBackPressed();
}
}
}
Mockup of your CanvassFragment showing the callback
public class CanvassFragment extends SherlockFragment {
public interface CanvassCallback {
public void itemSelected();
}
private CanvassCallback canvassCallback;
public void setCanvassCallback(CanvassCallback canvassCallback) {
this.canvassCallback = canvassCallback;
}
...
// The onClick of your item
private void onClick() {
// notify your activity that an item was selected
canvassCallback.itemSelected();
}
}
The registeredFragments are not strictly needed but I think it provides some value if your need to call methoods on your Fragment from activity.
public class TabsPagerAdapter extends FragmentStatePagerAdapter {
// see upvoted answer from http://stackoverflow.com/questions/8785221/retrieve-a-fragment-from-a-viewpager
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
private boolean canvassSelected = false;
private CanvassCallback canvassCallback;
public TabsPagerAdapter(FragmentManager fm, CanvassCallback canvassCallback) {
super(fm);
this.canvassCallback = canvassCallback;
}
public void canvassSelected() {
canvassSelected = !canvassSelected;
}
public boolean isCanvassSelected() {
return canvassSelected;
}
#Override
public SherlockFragment getItem(int index) {
switch (index) {
case 0:
if (canvassSelected)
return new ContactFragment();
CanvassFragment canvassFragment = new CanvassFragment();
// this ensures that your Activity gets notified when an item is clicked
canvassFragment.setCanvassCallback(canvassCallback);
return canvassFragment;
case 1:
return new TalkingPointsFragment();
case 2:
return new ContactFragment();
}
return null;
}
#Override
public int getCount() {
// get item count - equal to number of tabs
return 3;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Log.d(TAG, "instantiateItem " + position);
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
Log.d(TAG, "destroyItem " + position);
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
}
My problem is to initially load the fragment directly and also I want to call a method fragment is visible to the user.
For loading the correct fragment, I use viewPager.setCurrentItem() in onCreate. It works well.
FragmentActivity code:
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mTabsAdapter = new TabsPlayerAdapter(this, mRadioList);
mMainViewPager.setAdapter(mTabsAdapter);
mMainViewPager.setOnPageChangeListener(this);
mMainViewPager.setCurrentItem(2);
}
To a method called fragment Current, I use the onPageSelected viewPager. It works well.
FragmentActivity code:
#Override
public void onPageSelected(int position) {
Log.d(TAG, "onPageSelected - position: " + position);
((PlayerFragment) mTabsAdapter.mSparseFragment.get(position))
.startAnnimation();
}
FragmentStatePagerAdapter code:
#Override
public Fragment getItem(final int position) {
Log.d(TAG, "getItem - position: " + position);
Bundle args = new Bundle();
args.putString("num", mRadioModel.get(position).name);
mSparseFragment.put(position, Fragment.instantiate
(mContext,PlayerFragment.class.getName(), args));
return mSparseFragment.get(position);
}
FragmentStatePagerAdapter code :
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
Log.d(TAG, "destroyItem - position: " + position);
mSparseFragment.remove(position);
}
I can do these two things separately. But when I try to use the two together, I have a "NullPointerException" when I call my fragment.
I saw that onPageSelected is called before the getItem in my Adapter.
There is very easy work around:
In your adapter write:
public static interface FirstShot
{
public void onFirstShot();
}
private FirstShot firstShot;
private boolean shot = false;
#Override
public Fragment getItem(int arg0)
{
if (!shot && firstShot != null)
{
shot = true;
firstShot.onFirstShot();
}
// your code here
}
Now implement FirstShot in activity:
#Override
public void onFirstShot()
{
viewPager.post(new Runnable()
{
#Override
public void run()
{
boolean needNotify = false;
if (pager.getCurrentItem() == position) needNotify = true;
viewPager.setCurrentItem(position, false);
if (needNotify) onPageSelected(position);
}
});
}
onPageSelected() now calls!
You'll know that items are available when onAttachedToWindow is called. At the moment you call setCurrentItem, the adapter has not been used to create views yet. (setAdapter is not sufficient to know that all have been inflated)
Else, you can consider setting your listener after setting the currentItem, therefore not having a animation when opening the fragment.
The accepted solution didn't work for me, as I was still getting onPageSelected called before getItem created them.
I fixed it like so:
public class MyAdapter extends FragmentPagerAdapter {
...
...
#Override
public Fragment getItem(int position) {
Fragment fragment = createdFragments.get(position);
if (fragment != null) {
return fragment;
}
fragment = createNewFragment();
createdFragments.put(position, fragment);
return fragment;
}
public TabFragment getFragment(int position) {
TabFragment fragment = createdFragments.get(position);
if (fragment == null) {
fragment = (TabFragment) getItem(position);
}
return fragment;
}
}
and then I use adapter.getFragment() to get a fragment by code and never get a null value.