I'm new in android and want an app with viewpager. I am unable to design the viewpager in the layout. The layout fetch the data dynamatically. I want to create a matreial UI viewpager which swipes the page left or right like a paper.I have made a view which shows the data but is unable to swipe like a viewpager left or right...
The code is as below:
public class DetailNewsActivity extends AppCompatActivity {
private PullToZoomScrollViewEx scrollView;
private ArrayList<NewsItemModel> newsArr;
private TextView tvNewsTitle;
private TextView tvNewsPublishDate;
private TextView tvNewsFull;
private int newsPosition = 0;
private ImageView ivYoutubeEnable;
private SharedPreferences sharedPref;
int textSize = 16;
boolean isHighQuality = false;
private Typeface typeface;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail_news);
init();
AdView mAdView = (AdView) findViewById(R.id.adView);
AdRequest adRequest = new AdRequest.Builder()
.addTestDevice("5745FD6726ACCBEE8324DB158D021FA5")
.build();
mAdView.loadAd(adRequest);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_detail_news, container, false);
return view;
}
private void init() {
typeface = Typeface.createFromAsset(getAssets(), "AnmolUni.ttf");
// newsArr = (ArrayList<NewsItemModel>) getIntent().getSerializableExtra("newsArray");
newsArr = AppController.getAppController().getMainNewsArr();
AppController.getAppController().setMainNewsArr(null);
newsPosition = getIntent().getIntExtra("newsPosition", 0);
findViewById(R.id.iv_back).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
findViewById(R.id.iv_share).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
generateBranchURL(newsPosition);
}
});
sharedPref = getSharedPreferences(Constants.SHARED_PREF_NAME, Context.MODE_PRIVATE);
textSize = sharedPref.getInt("text_size", 16);
isHighQuality = sharedPref.getBoolean("isHighQuality",false);
loadViewForCode();
scrollView = (PullToZoomScrollViewEx) findViewById(R.id.scroll_view);
setNewsFromArray(newsPosition);
// ((ImageView) scrollView.getZoomView().findViewById(R.id.iv_zoom)).setImageResource(android.R.drawable.arrow_down_float);
(scrollView.getZoomView().findViewById(R.id.iv_zoom)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(DetailNewsActivity.this, ImageVideoActivity.class);
intent.putExtra("viewType", "image");
if(isHighQuality)
intent.putExtra("imageArr", newsArr.get(newsPosition).getImage());
else
intent.putExtra("imageArr", newsArr.get(newsPosition).getMedium());
startActivity(intent);
}
});
DisplayMetrics localDisplayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(localDisplayMetrics);
int mScreenHeight = localDisplayMetrics.heightPixels;
int mScreenWidth = localDisplayMetrics.widthPixels;
LinearLayout.LayoutParams localObject = new LinearLayout.LayoutParams(mScreenWidth, (int) (9.0F * (mScreenWidth / 16.0F)));
scrollView.setHeaderLayoutParams(localObject);
scrollView.setParallax(true);
// scrollView.getPullRootView().findViewById(R.id.container_layout).setOnTouchListener(new OnSwipeTouchListener(DetailNewsActivity.this) {
scrollView.getPullRootView().setOnTouchListener(new OnSwipeTouchListener(DetailNewsActivity.this) {
#Override
public void onSwipeLeft() {
if (newsPosition < newsArr.size() - 1) {
newsPosition++;
setNewsFromArray(newsPosition);
} else {
CommonUtils.showToast(DetailNewsActivity.this, "No more news");
}
}
#Override
public void onSwipeRight() {
if (newsPosition > 0) {
newsPosition--;
setNewsFromArray(newsPosition);
} else {
CommonUtils.showToast(DetailNewsActivity.this, "This is the first news");
}
}
});
scrollView.setOnPullZoomListener(new PullToZoomBase.OnPullZoomListener() {
#Override
public void onPullZooming(int newScrollValue) {
Log.d("MainActivity", "onPullZooming: " + newScrollValue);
// Intent intent = new Intent(DetailNewsActivity.this, ImageVideoActivity.class);
// intent.putExtra("viewType", "image");
// intent.putExtra("imageArr", newsArr.get(newsPosition).getImage());
// startActivity(intent);
}
#Override
public void onPullZoomEnd() {
}
});
}
void setNewsFromArray(int position) {
if (position >= newsArr.size()) {
finish();
return;
}
if (!newsArr.get(position).getMedium().get(0).isEmpty()) {
if(isHighQuality)
Picasso.with(DetailNewsActivity.this).load(newsArr.get(position).getImage().get(0)).placeholder(R.drawable.logo).error(R.drawable.logo).
into((ImageView) scrollView.getZoomView().findViewById(R.id.iv_zoom));
else
Picasso.with(DetailNewsActivity.this).load(newsArr.get(position).getMedium().get(0)).placeholder(R.drawable.logo).error(R.drawable.logo).
into((ImageView) scrollView.getZoomView().findViewById(R.id.iv_zoom));
} else {
((ImageView) scrollView.getZoomView().findViewById(R.id.iv_zoom)).setImageResource(R.drawable.logo);
}
tvNewsTitle.setText(newsArr.get(position).getTitle());
tvNewsPublishDate.setText(newsArr.get(position).getPublish_dt());
//String style = "<html><body style='text-align:justify'>";
//Log.i("RAJEEV",style + newsArr.get(position).getFullnews());
tvNewsFull.setText(Html.fromHtml( newsArr.get(position).getFullnews()));
if (newsArr.get(position).getYoutube_video().isEmpty()) {
ivYoutubeEnable.setVisibility(View.GONE);
} else {
ivYoutubeEnable.setVisibility(View.VISIBLE);
}
ivYoutubeEnable.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(DetailNewsActivity.this, ImageVideoActivity.class);
intent.putExtra("viewType", "youtube");
intent.putExtra("youtube_code", newsArr.get(newsPosition).getYoutube_video());
startActivity(intent);
}
});
}
private void loadViewForCode() {
PullToZoomScrollViewEx scrollView = (PullToZoomScrollViewEx) findViewById(R.id.scroll_view);
View headView = LayoutInflater.from(this).inflate(R.layout.ptz_head_view, null, false);
View zoomView = LayoutInflater.from(this).inflate(R.layout.ptz_zoom_view, null, false);
View contentView = LayoutInflater.from(this).inflate(R.layout.ptz_content_view, null, false);
scrollView.setHeaderView(headView);
scrollView.setZoomView(zoomView);
scrollView.setScrollContentView(contentView);
tvNewsTitle = (TextView) scrollView.getPullRootView().findViewById(R.id.tv_news_title);
tvNewsPublishDate = (TextView) scrollView.getPullRootView().findViewById(R.id.tv_news_publish_date);
tvNewsFull = (TextView) scrollView.getPullRootView().findViewById(R.id.tv_news_full);
tvNewsFull.setTextSize(textSize);
if (!AppController.isPunjabiSupported()) {
tvNewsTitle.setTypeface(typeface);
tvNewsFull.setTypeface(typeface);
}
ivYoutubeEnable = (ImageView) scrollView.getHeaderView().findViewById(R.id.iv_youtube_header);
}
void generateBranchURL(final int newsPosition) {
// String imageUrl = "";
// if (newsArr.get(newsPosition).getMedium().size() <= 1)
// imageUrl = newsArr.get(newsPosition).getMedium().get(0);
BranchUniversalObject branchUniversalObject = new BranchUniversalObject()
.setCanonicalIdentifier("NewsDetails")
///.setCanonicalUrl("https://branch.io/deepviews")
//.setTitle("" + newsArr.get(newsPosition).getTitle())
//.setContentDescription("" + newsArr.get(newsPosition).getIntro())
//.setContentImageUrl("" + imageUrl)
// You use this to specify whether this content can be discovered publicly - default is public
.setContentIndexingMode(BranchUniversalObject.CONTENT_INDEX_MODE.PUBLIC);
// Here is where you can add custom keys/values to the deep link data
//.addContentMetadata("property1", "blue")
//.addContentMetadata("property2", "red");
LinkProperties linkProperties = new LinkProperties()
.addControlParameter("$desktop_url", "http://www.newsnumber.com/news/share/" + newsArr.get(newsPosition).getFn_id())
.addControlParameter("$ios_url", "itms-apps://itunes.apple.com/us/app/newsnumber/id1022442357?mt=8")
.addControlParameter("NewsId", "" + newsArr.get(newsPosition).getFn_id())
.addControlParameter("CatId", "" + newsArr.get(newsPosition).getCat_id())
.addControlParameter("$og_title", newsArr.get(newsPosition).getTitle())
.addControlParameter("$og_description", newsArr.get(newsPosition).getIntro())
.addControlParameter("$og_image_url", newsArr.get(newsPosition).getImage().get(0))
.addControlParameter("$twitter_title", newsArr.get(newsPosition).getTitle())
.addControlParameter("$twitter_description", newsArr.get(newsPosition).getIntro())
.addControlParameter("$twitter_image_url", newsArr.get(newsPosition).getImage().get(0))
;
branchUniversalObject.generateShortUrl(this, linkProperties, new Branch.BranchLinkCreateListener() {
#Override
public void onLinkCreate(String url, BranchError error) {
if (error == null) {
Log.i("MyApp", "got my Branch link to share: " + url);
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, "News Number\n");
sharingIntent.putExtra(Intent.EXTRA_TEXT, url);
startActivity(Intent.createChooser(sharingIntent, "Share via"));
}
}
});
}
}
can anyone help??
thanks in advance.
It seems like you might be trying to make a new Activity for each "page" of a ViewPager. The Android support library already has their own ViewPager that uses fragments.
You basically need three things to use a ViewPager:
The ViewPager itself
An adapter for the ViewPager
The fragment that will be used in the ViewPager (esentially the "template" that will be used for each "page" in the ViewPager)
First, we'll create the fragment. This is just a simple example that uses only one TextView, but it will work for any amount of views and data. You'll notice that static method "newInstance()" that creates and returns an instance of this fragment. Google recommends using this method to instantiate new Fragments for a ViewPager as it makes passing data to the fragment much easier. All fragments have a "setArguments()" method that lets you pass in a Bundle when you instantiate it with whatever data you want. The method "getArguments()" can be used to access that bundle and get the values out of it in onCreate() or onCreateView(). This is how you pass in an object or objects to bind its data to the views. In this example, were just passing in a String and setting that String to a TextView. You'll see how it's used when we create the adapter for the ViewPager.
//You should be using android.support.v4.app.Fragment here
public class ExampleFragment extends Fragment {
private static final String DAY_NAME_KEY = "day_name";
private TextView dayName;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater,
#Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.fragment_example, container, false);
dayName = (TextView) fragmentView.findViewById(R.id.day_name);
return fragmentView;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//Set the name of the day to the dayName TextView
String day = getArguments().getString(DAY_NAME_KEY);
dayName.setText(day);
}
public static ExampleFragment newInstance(String day) {
Bundle bundle = new Bundle();
bundle.putString(DAY_NAME_KEY, day);
ExampleFragment fragment = new ExampleFragment();
fragment.setArguments(bundle);
return fragment;
}
}
Now, we need to make an adapter that will create the views when the ViewPager is swiped. You need to extend either FragmentPagerAdapter or FragmentStatePagerAdapter. FragmentPagerAdapter is used for a small number of static fragments and it will use more memory. So you only want to use this if you have 4 or 5 pages and aren't adding any more dynamically.
For your case, it sounds like you want to swipe through a variable number of pages that are dynamically added, so you want to use FragmentStatePagerAdapter. It's optimized for memory efficiency and it will handle the saving and restoring of the fragments' state for you.
The adapter is simple.
First, you need to make your constructor match the super class's constructor. What that means is that your constructor must have a FragmentManager parameter. All you do with that is pass it to the super class. (You'll see below.)
Secondly, you have to implement just 2 methods from the FragmentStatePagerAdapter class:
public Fragment getItem(int position)
and
public int getCount()
getItem will be automatically called by the ViewPager when it is swiped. You just have to tell it what type of fragment to return. We'll be using the newInstance() method from the ExampleFragment class here.
getCount is the number of views that your ViewPager will be using. For example, I will have an ArrayList that will contain 7 strings (one for each day of the week). I want each one of those strings to be displayed on a different page of my ViewPager. So I'm just going to return the size of the ArrayList for this method.
Here's the class:
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
//A reference to the array of data that will be used to populate
//each fragment. In this case it's an array of Strings, but it
//could be any type of object. The Strings within this array are what
//we'll be passing to the newInstance() method of each fragment.
private ArrayList<String> days;
//Constructor must take a FragmentManager to match the superclass.
public ViewPagerAdapter(FragmentManager fm, ArrayList<String> days) {
//All you have to do with the fragment manager is pass it to super
super(fm);
//The array will be passed in when we create the Adapter in our Activity
this.days = days;
}
#Override
public Fragment getItem(int position) {
/*
Automatically called when another page is needed.
The adapter will keep track of the position of the current page
so the first time this is called, it will be 0, then when a
swipe occurs, it will be one. If it is swiped backward, it will go back to 0.
So when the position is 0, a new Fragment will be created and the
String at days.get(0) ("Monday") will be passed to it.
*/
return ExampleFragment.newInstance(days.get(position));
}
#Override
public int getCount() {
return days.size();
}
}
Now we just have to set the adapter for the ViewPager in our Activity and it will automatically handle swipes for us.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<String> daysOfWeek = new ArrayList<>();
daysOfWeek.add("Monday");
daysOfWeek.add("Tuesday");
daysOfWeek.add("Wednesday");
daysOfWeek.add("Thursday");
daysOfWeek.add("Friday");
daysOfWeek.add("Saturday");
daysOfWeek.add("Sunday");
ViewPager pager = findViewById(R.id.view_pager);
//Pass the activity's fragmentmanager by calling getSupportFragmentManager().
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager(), daysOfWeek);
pager.setAdapter(adapter);
}
}
This is what we get (I've added some padding and color to make it clear):
As for changing the way the pages "turn" (for example, like a newspaper), you need to look into PageTransformer
Related
I have implemented tabs functionality via SmartTabLayout library in my android application. At present I have used same fragment as viewpager for both of my tabs. Since, the only difference is the view is that sorting of listitems. Below is my HomeActivity code:
HomeActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
final ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
final SmartTabLayout viewPagerTab = (SmartTabLayout) findViewById(R.id.viewpagertab);
viewPagerTab.setCustomTabView(this);
FragmentPagerItems pages = new FragmentPagerItems(this);
pages.add(FragmentPagerItem.of("Test1", SampleFragment.class));
pages.add(FragmentPagerItem.of("Test2", SampleFragment.class));
FragmentStatePagerItemAdapter adapter = new FragmentStatePagerItemAdapter(
getSupportFragmentManager(), pages);
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(0);
viewPagerTab.setViewPager(viewPager);
}
#Override
public View createTabView(ViewGroup container, int position, PagerAdapter adapter) {
LayoutInflater inflater = LayoutInflater.from(container.getContext());
View tab = inflater.inflate(R.layout.custom_tab_icon_and_notification_mark, container, false);
TextView txtTab=(TextView)tab.findViewById(R.id.txtTitle);
switch (position){
case 0:txtTab.setText("Test1");break;
case 1:txtTab.setText("Test2");break;
default:throw new IllegalStateException("Invalid pos - "+ position);
}
return tab;
}
My SampleFragment.java is as below wherein I do some server request for data and update the listview adapter.
SampleFragment.java
List<Items> lstItems=new ArrayList<>();
static ItemListAdapter mAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view= inflater.inflate(R.layout.fragment_sample, container, false);
ListView lstviewItems = (ListView) view.findViewById(R.id.lstItems);
int position = FragmentPagerItem.getPosition(getArguments());
View emptyView=view.findViewById(R.id.emptyList);
lstviewItems.setEmptyView(emptyView);
mAdapter = new ItemsListAdapter(getActivity(),lstItems);
lstviewItems.setAdapter(mAdapter);
switch (position){
case 0:
//JsonObjectRequest
loadItems();
break;
case 1:
//sort the loaded items
break;
}
return view;
}
private void loadItems(){
try {
JsonArrayRequest request = new JsonArrayRequest(Request.Method.GET,url, null,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
lstItems.clear();
for (int i = 0; i < response.length(); i++) {
//Add item to lstItems
}
mAdapter.notifyDataSetChanged();
}
}
});
testApp.getInstance().addToRequestQueue(request);
} catch (Exception ex) {
ex.printStackTrace();
}
}
But even after mAdapter.notifyDataSetChanged() the listview in the current viewPager tab i.e. Test1 tab is not getting refreshed. Whereas when I navigate to Test2 tab, I can see the changes in the listview, where is data has been loaded properly. Below is the screenshot for 2 different tabs.
I've also searched for this problem and found other solution which did not work for me. One of the solution being, adding a refresh method in ItemsAdapter as below:
public void refresh(List<Items> items)
{
this.items = items;
notifyDataSetChanged();
}
and instead of mAdapter.notifyDataSetChanged() I used mAdapter.refresh(lstItems);. But unfortunately it did not work either. How can I possibly overcome this. Please let me know if I have to add furthermore details on this.
I think your problem is here:
mAdapter = new ItemsListAdapter(getActivity(),lstItems);
You create a new instance of ItemsListAdapter and bind it to the listview with
lstviewItems.setAdapter(mAdapter);
The problem is that this adapter is static. So if you create a new instance you destroy the old adapter and the listview of the other tab has not the adapter anymore that updates your data.
EDIT:
I'd recommend to load the data on a central place. Add the response (your data objects) to a manager class. Then implement on every view which using this data a callback (lets say JsonDataChangedCallback). Register the classes which implementing the callback to the manager with Manager.getInstance().registerCallback(). Then every time your data is changed call updateCallbacks() in your manager and all views will be updated. That's the way implemented that process in my app and it works.
Sample Code:
public class CDMMovieManager {
private CDMMovieManager() {
m_Movies = new ArrayList<>();
m_MovieChangedCallbacks = new ArrayList<>();
}
public static synchronized CDMMovieManager getInstance() {
if(ms_Instance == null)
ms_Instance = new CDMMovieManager();
return ms_Instance;
}
public void addMovie(CDMMovie p_Movie) {
m_Movies.add(p_Movie);
notifyCallbacks();
}
/**
* Registers a movie changed callback
*
* #param p_MovieChangedCallback the callback to register
*/
public void registerMovieChangedCallback(IDMMovieChangedCallback p_MovieChangedCallback) {
m_MovieChangedCallbacks.add(p_MovieChangedCallback);
}
/**
* Removes a movie changed callback
*
* #param p_MovieChangedCallback the callback to remove
*/
public void removeMovieChangedCallback(IDMMovieChangedCallback p_MovieChangedCallback) {
m_MovieChangedCallbacks.remove(p_MovieChangedCallback);
}
private void notifyCallbacks() {
for(IDMMovieChangedCallback l_MovieChangedCallback : m_MovieChangedCallbacks) {
l_MovieChangedCallback.onMoviesChanged();
}
}
}
And the implementing Class:
public class CDMBasicMovieFragment extends Fragment implements IDMMovieChangedCallback {
//...
#Override
public void onMoviesChanged() {
m_Adapter.notifyDataSetChanged();
}
}
I want to show 3 different views in ViewPager and I want to navigate between them with bottom navigation bar. But I have a serious performance problem. When I tried to switch the view, it switches with laggy swipe and I think it's because every fragment is re-created everytime I switch or it's because I didn't figure onPageSelected method out. I couldn't fix it.
Here is my codes.
MainActivity.java
public class MainActivity extends FragmentActivity {
private BottomBar mBottomBar;
private User currentUser;
private NonSwipeableViewPager viewPager;
private Context context;
private FragmentAdapter fragAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
// To retrieve object in second Activity
currentUser = (User) getIntent().getSerializableExtra("currentUser");
//initialize views
initView();
//bottom bar
mBottomBar = BottomBar.attach(this, savedInstanceState);
mBottomBar.noTabletGoodness();
//mBottomBar.setActiveTabColor(R.color.app_design_color);
mBottomBar.setItems(R.menu.bottombar_menu);
mBottomBar.setActiveTabColor("#6c4853");
//mBottomBar.setBottom(1);
mBottomBar.setOnMenuTabClickListener(new OnMenuTabClickListener() {
#Override
public void onMenuTabSelected(#IdRes int menuItemId) {
if (menuItemId == R.id.bottomContacts) {
// The user selected item number one.
setPage(Constants.CONTACTS_NUM);
}else if (menuItemId == R.id.bottomQR) {
// The user selected item number two.
//setAdapterClick(Constants.ADD_NUM);
}else if (menuItemId == R.id.bottomProfile) {
// The user selected item number three.
setPage(Constants.PROFILE_NUM);
}
}
#Override
public void onMenuTabReSelected(#IdRes int menuItemId) {
if (menuItemId == R.id.bottomContacts) {
// The user selected item number one.
}else if (menuItemId == R.id.bottomQR) {
// The user selected item number one.
}else if (menuItemId == R.id.bottomProfile) {
// The user selected item number one.
}
}
});
}
private void initView(){
viewPager = (NonSwipeableViewPager) findViewById(R.id.viewpager);
fragAdapter = new FragmentAdapter(getSupportFragmentManager(), currentUser, context);
viewPager.setAdapter(fragAdapter);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Necessary to restore the BottomBar's state, otherwise we would
// lose the current tab on orientation change.
mBottomBar.onSaveInstanceState(outState);
}
private void setPage(final int pageNum){
viewPager.setCurrentItem(pageNum, true);
Global.setCurrentPageNum(pageNum);
}
private void setAdapterClick(int no){
switch (no){
case Constants.CONTACTS_NUM :
setPage(Constants.CONTACTS_NUM);
break;
case Constants.ADD_NUM :
setPage(Constants.ADD_NUM);
break;
case Constants.PROFILE_NUM :
setPage(Constants.PROFILE_NUM);
break;
}
}
}
FragmentAdapter.java
public class FragmentAdapter extends FragmentPagerAdapter{
private Context context;
private User currentUser;
private FragmentManager fm;
public FragmentAdapter(FragmentManager fm, User currentUser, Context context) {
super(fm);
this.fm = fm;
this.context = context;
this.currentUser = currentUser;
}
#Override
public Fragment getItem(int position) {
switch (position){
case 0 :
return new ContactsFragment().newInstance(context, currentUser);
case 1 :
return new ContactsFragment().newInstance(context, currentUser);
case 2 :
return new ProfileFragment().newInstance(context, currentUser);
default :
return new ContactsFragment().newInstance(context, currentUser);
}
}
#Override
public int getCount() {
return 3;
}
}
One of my Fragments:
public class ContactsFragment extends Fragment{
// Store instance variables
private Context context;
private User currentUser;
private View actionView;
private View contactsView;
// newInstance constructor for creating fragment with arguments
public static ContactsFragment newInstance(Context context, User currentUser) {
ContactsFragment fragmentFirst = new ContactsFragment();
Bundle args = new Bundle();
args.putSerializable("currentUser", currentUser);
fragmentFirst.setArguments(args);
return fragmentFirst;
}
// Store instance variables based on arguments passed
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.context = getActivity();
this.currentUser = (User) getArguments().getSerializable("currentUser");
}
// Inflate the view for the fragment based on layout XML
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if(contactsView == null){
contactsView = inflater.inflate(R.layout.contacts_layout, container, false);
RecyclerView recyclerView = (RecyclerView) contactsView.findViewById(R.id.recycler_view);
LinearLayoutManager lLayout = new GridLayoutManager(context, 1);
recyclerView.addItemDecoration(new DividerItemDecoration(context, R.drawable.divider));
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(lLayout);
recyclerView.setAdapter(new CategoryAdapter(context, currentUser.categories));
}
return contactsView;
}
}
Edit:
If I disable animation while setting current item, there is no problem. But I want to use animation.
Try adding this line after you setting adapter for your ViewPager in initView()
viewPager.setOffScreenPageLimit(3);
The following method is alreday provided by ViewPager class in Android
/**
* 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.
*
* <p>This is offered as an optimization. If you know in advance the number
* of pages you will need to support or have lazy-loading mechanisms in place
* on your pages, tweaking this setting can have benefits in perceived smoothness
* of paging animations and interaction. If you have a small number of pages (3-4)
* that you can keep active all at once, less time will be spent in layout for
* newly created view subtrees as the user pages back and forth.</p>
*
* <p>You should keep this limit low, especially if your pages have complex layouts.
* This setting defaults to 1.</p>
*
* #param limit How many pages will be kept offscreen in an idle state.
*/
public void setOffscreenPageLimit(int limit) {
if (limit < DEFAULT_OFFSCREEN_PAGES) {
Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +
DEFAULT_OFFSCREEN_PAGES);
limit = DEFAULT_OFFSCREEN_PAGES;
}
if (limit != mOffscreenPageLimit) {
mOffscreenPageLimit = limit;
populate();
}
}
One More thing I have noticed inside your code is that you are using getIntentSearializableExtra() cuz you are using Serializable to transport data inside your activity and also in Fragment.
Please Don't Do this try to use Serializable Use Parcelable and getParcelableExtra()
Please consider this link http://www.3pillarglobal.com/insights/parcelable-vs-java-serialization-in-android-app-development
this is why i am suggesting you to use Parcelable.
I have created two fragments in a ViewPager , when I click on first one , Second fragment is taking the click.
This issue puts me in another position, when I create two instance from same fragment but with different data.
{
#Override
public Fragment getItem(int index) {
switch (index) {
case 1:
return FragmentBrandList.getInstance(tabs.getBrandList2(), 19,
title);
case 0:
return FragmentBrandList.getInstance(tabs.getBrandList1(), 19,
title);
}
return null;
}
#Override
public int getCount() {
return 2;
}
}
After creating ViewPager , both the fragments get created correctly , but when I click on any thing in the first fragment , the click event gets fired in second fragment not in the first fragment.
EDIT
public class TabsPagerAdapter extends FragmentPagerAdapter {
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 1:
return FragmentBrandList.getInstance(tabs.getBrandList2(), 19,
title);
case 0:
return FragmentBrandList.getInstance(tabs.getBrandList1(), 19,
title);
}
return null;
}
#Override
public int getCount() {
return 2;
}
in FragmentBrandList
public class FragmentBrandList extends Fragment {
ArrayList<Brand> brandList = new ArrayList<Brand>();
int discoverID;
RecyclerView listView;
LinearLayoutManager mLayoutManager;
public static FragmentBrandList getInstance(ArrayList<Brand> brandList,
int discoverID, String title) {
FragmentBrandList frag = new FragmentBrandList();
Bundle b = new Bundle();
b.putSerializable("brandList", brandList);
b.putInt("discoverID", discoverID);
b.putString("title", title);
frag.setArguments(b);
return frag;
}
public FragmentBrandList() {
}
String title = "";
View v;
boolean isInflated = false;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (v == null) {
v = inflater.inflate(R.layout.fragment_list_view_brownbg,
container, false);
isInflated = true;
} else {
isInflated = false;
((ViewGroup) v.getParent()).removeView(v);
}
return v;
}
MainActivity activity;
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (isInflated) {
activity = (MainActivity) getActivity();
initView();
}
}
public void initView(){
title = getArguments().getString("title");
discoverID = getArguments().getInt("discoverID");
listView = (RecyclerView) v.findViewById(R.id.listView);
mLayoutManager = new LinearLayoutManager(getActivity());
listView.setItemAnimator(new DefaultItemAnimator());
listView.setHasFixedSize(true);
listView.setLayoutManager(mLayoutManager);
listView.setAdapter(new BrandListRecAdapter(getActivity(),
R.layout.single_item_listview, brandList));
}
#Override
public void onResume() {
// handle on click
((BrandListRecAdapter) listView.getAdapter())
.setOnItemClickListener(new ItemClickListener() {
#Override
public void onItemClickListener(final int pos, View v) {
activity.replaceCurrentFragment(
FragmentBrandDetails.getInstance(
brandList.get(pos), "bank"), true,
true);
}}
EDIT
i think problem cause
when create second fragment , listview.onclick is overwrite first one !!
how can solve this peb?
EDIT
thank you to every one try to help me
problem is already because i use same adapter and same fragment
when second fragment created it is overwrite on item click
so when click in item is called second one !!!
Just put this android:clickable="true" in every fragment layout, and this will not happen again.
This is just an educated guess, but because a ViewPager will always create at least one extra Fragment on either side of the currently visible fragment, you may be creating two virtually identical Fragments in parallel, assigning them both onItemClickListeners in onResume and as such they are both responding to item clicks when an item is pressed on either Fragment.
You could try moving the onItemClickListener to the ViewHolder in your Adapter, rather assigning it in onResume. In addition, I wonder what a Brand object looks like in your RecyclerView, and whether it wouldn't be simpler to pass the current ViewPager page as a parameter in getInstance, and use this to access an Array containing the information necessary to fill your RecyclerView rows.
Here is a very brief example of how your ViewHolder may look:
class MyRecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
public MyRecyclerViewHolder(View itemView) {
itemView.setOnClickListener(this);
//etc.
I have 2 fragments (tabs) that share some data. When one changes the data, I'd like to have that reflected on the other tab. I researched this on stackOverflow and I think the relevant answer has to do with a .notifyDataSetChanged() call, but I can't make it work. Here's the relevant code...
public class EnterCourseData extends FragmentActivity implements ActionBar.TabListener {
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
// Tab titles
private String[] tabs = { "Pars", "Handicaps" };
private int courseNumber, teeNumber;
private Tee tee;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_enter_tees);
// Initilization
Intent mIntent = getIntent();
courseNumber = mIntent.getIntExtra("courseNumber",0);
Course course = Global.getCourse(courseNumber);
teeNumber = mIntent.getIntExtra("teeNumber",0);
tee = course.getTee(teeNumber);
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
mAdapter = new TabsPagerAdapter(getSupportFragmentManager(), courseNumber, teeNumber);
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Adding Tabs
for (String tab_name : tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name)
.setTabListener(this));
}
/**
* on swiping the viewpager make respective tab selected
* */
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
and further down, here is the onClick method that necessitates the refresh...
public void savePars(View view){
tee.setSlope(Integer.parseInt(((EditText) findViewById(R.id.enter_tee_slope)).getText().toString()));
tee.setRating(Double.parseDouble(((EditText) findViewById(R.id.enter_tee_rating)).getText().toString()));
mAdapter.notifyDataSetChanged();
}
Here is the TabsPagerAdapter...
public class TabsPagerAdapter extends FragmentPagerAdapter {
int courseNumber, teeNumber;
public TabsPagerAdapter(FragmentManager fm, int courseNumber, int teeNumber) {
super(fm);
this.courseNumber = courseNumber;
this.teeNumber = teeNumber;
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
// Par Entry activity
Fragment parFragment = new ParFragment();
Bundle args = new Bundle();
args.putInt(ParFragment.ARG_COURSE_NUMBER, courseNumber);
args.putInt(ParFragment.ARG_TEE_NUMBER, teeNumber);
parFragment.setArguments(args);
return parFragment;
case 1:
// Handicap Entry fragment activity
Fragment hcpFragment = new HandicapFragment();
args = new Bundle();
args.putInt(HandicapFragment.ARG_COURSE_NUMBER, courseNumber);
args.putInt(HandicapFragment.ARG_TEE_NUMBER, teeNumber);
hcpFragment.setArguments(args);
return hcpFragment;
}
return null;
}
#Override
public int getCount() {
// get item count - equal to number of tabs
return 2;
}
}
Here is one Fragment...
public class ParFragment extends Fragment {
public static final String ARG_COURSE_NUMBER = "courseNumber", ARG_TEE_NUMBER = "teeNumber";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_par, container, false);
Bundle args = getArguments();
Course course = Global.getCourse(args.getInt(ARG_COURSE_NUMBER));
((TextView) rootView.findViewById(R.id.display_course_name)).setText(course.getName());
Tee tee = course.getTee(args.getInt(ARG_TEE_NUMBER));
((TextView) rootView.findViewById(R.id.display_tee_name)).setText(tee.getTeeName());
((TextView) rootView.findViewById(R.id.enter_tee_slope)).setText(Integer.toString(tee.getSlope()));
((TextView) rootView.findViewById(R.id.enter_tee_rating)).setText(Double.toString(tee.getRating()));
return rootView;
}
}
And here is the other...
public class HandicapFragment extends Fragment {
public static final String ARG_COURSE_NUMBER = "courseNumber", ARG_TEE_NUMBER = "teeNumber";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_handicap, container, false);
Bundle args = getArguments();
Course course = Global.getCourse(args.getInt(ARG_COURSE_NUMBER));
((TextView) rootView.findViewById(R.id.display_course_name)).setText(course.getName());
Tee tee = course.getTee(args.getInt(ARG_TEE_NUMBER));
((TextView) rootView.findViewById(R.id.display_tee_name)).setText(tee.getTeeName());
((TextView) rootView.findViewById(R.id.enter_tee_slope)).setText(Integer.toString(tee.getSlope()));
((TextView) rootView.findViewById(R.id.enter_tee_rating)).setText(Double.toString(tee.getRating()));
return rootView;
}
}
When the button is clicked, I want to save the values and I want these values to show up on the other fragment.
Help a noob out.
Thanks
You need to communicate between fragments, but a fragment cannot directly communicate with other fragment, all the communication should be done through the activity which holds these fragments.
The steps to follow are :
Define an Interface in the fragment where you have implemented the onClickListener (let it be Fragment A)
Implement the Interface in the activity which holds these fragments
In the method overridden, retrieve the fragment instance from the viewpager adapter and deliver a message to Fragment B by calling it's public methods.
refer this answer to retrieve fragment instance from adapter
For more details about Communicating with Other Fragments, refer here
So there is a trick: just let the fragments have the object reference of one another and call the other's function to load data when you handle the onClickListener of the button.
E.g:
protected void onClickListener(View view) {
if (view == myButton) {
// Do other stuffs here
fragment1.reloadData();
}
}
P/S : I re-post this as answer to have the code formatter.
I am developing a small application consisting of several tabs where each tab holds just one kind of products (for example pizza products) and makes it possible to add specific product (Margherita) from this tab to an order. Each tab holds layout where there are buttons representing each product on the left side and list of items (all products) currently added to the order + calculated prices on the right side. This is the way how I currently add Tab in TabHost:
Bundle extras = new Bundle();
extras.putString("productType", "pizza");
tabHost.addTab(tabHost.newTabSpec("pizza").setIndicator("Pizza"), OrderFragment.class, extras);
The problem is that when I try to get arguments in a constructor of OrderFragment, it throws an exception:
E/AndroidRuntime(533): FATAL EXCEPTION: main
E/AndroidRuntime(533): java.lang.NullPointerException
The reason why I need to pass some data to the OrderFragment is that OrderFragment is GOING to be an abstract class for any kind of product (product, pasta, etc.), so it can find out, for which type of product it is and load proper data for that. I thought that the method addTab(TabSpec, Class<T>, Bundle) creates an instance of specified class and puts extras in it but it seems like that these extras are not packed with it. (Guess it is for another purpose). I would appreciate any suggestions how to solve this. If you would do it in completely different way, I would also appreciate pointing it out.
OrderFragment:
public class OrderFragment extends Fragment implements IEditOrder{
private static final String TAG = "OrderFragment";
private Controller controller;
private ListView lst_order;
private TextView txt_order_total;
private Button btn_finishOrder;
private Button btn_cancelOrder;
private String productType;
private OrderAdapter orderAdapter;
private static final int DIALOG_EDIT_ORDER = 1;
public OrderFragment() {
Bundle extras = getArguments();
Log.d(TAG, "Extras: " + extras.toString());
this.productType = extras.getString("productType");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//setRetainInstance(true);
controller = Controller.getInstance();
controller.loadProducts(getActivity().getApplicationContext());
//FillDatabase.loadDataToDatabase(getActivity());
}
#Override
public void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_pizza, container, false);
txt_order_total = (TextView)view.findViewById(R.id.txt_order_total);
btn_finishOrder = (Button)view.findViewById(R.id.btn_finishOrder);
btn_cancelOrder = (Button)view.findViewById(R.id.btn_cancelOrder);
btn_finishOrder.setOnClickListener(finishOrder);
btn_cancelOrder.setOnClickListener(cancelOrder);
final RelativeLayout layout = (RelativeLayout) view.findViewById(R.id.rl_order_pizza);
orderAdapter = new OrderAdapter(getActivity(), controller.getOrderMap());
lst_order = (ListView) view.findViewById(R.id.lst_order);
lst_order.addHeaderView(inflater.inflate(R.layout.order_list_header, null));
lst_order.setAdapter(orderAdapter);
lst_order.setOnItemClickListener(itemClickListener);
txt_order_total.setText("Total Price: " + controller.calculateTotalPrice());
layout.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
layout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
RelativeLayout.LayoutParams layoutParams;
int currentX = 20;
int currentY = 20;
for (Product product: controller.getProducts("pizza")){
layoutParams = new RelativeLayout.LayoutParams(UIConstnts.BUTTON_WIDTH, UIConstnts.BUTTON_HEIGHT);
Button tempButton = new Button(getActivity().getApplicationContext());
tempButton.setId((int)product.getId());
tempButton.setText(product.getName());
tempButton.setOnClickListener(clickListener);
layoutParams.setMargins(currentX, currentY, 0, 0);
tempButton.setLayoutParams(layoutParams);
layout.addView(tempButton);
if (layout.getWidth() < currentX + UIConstnts.MARGIN_LEFT + (2 * UIConstnts.BUTTON_WIDTH)){
currentX = 20;
currentY += UIConstnts.BUTTON_HEIGHT + UIConstnts.MARGIN_BOTTOM;
}
else{
currentX += UIConstnts.MARGIN_LEFT + UIConstnts.BUTTON_WIDTH;
}
}
layout.requestLayout();
}
});
return view;
}
private OnClickListener clickListener = new OnClickListener(){
#Override
public void onClick(View view) {
controller.addOrderItem(1, (long)view.getId());
updateQuantity();
txt_order_total.setText("Total Price: " + controller.calculateTotalPrice());
}
};
private OnItemClickListener itemClickListener = new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
showDialog(id, Integer.valueOf(((TextView)view.findViewById(R.id.txt_lst_quantity)).getText().toString()));
}
};
private OnClickListener finishOrder = new OnClickListener(){
#Override
public void onClick(View v) {
controller.finishOrder(getActivity());
updateQuantity();
}
};
private OnClickListener cancelOrder = new OnClickListener(){
#Override
public void onClick(View v) {
controller.resetOrder();
updateQuantity();
}
};
private void showDialog(long productId, int quantity) {
DialogFragment newFragment = EditOrderDialog.newInstance(productId, quantity, "Change Quantity");
newFragment.setTargetFragment(this, DIALOG_EDIT_ORDER);
newFragment.show(getFragmentManager(), "dialog");
}
#Override
public void updateQuantity() {
orderAdapter.setOrderList(controller.getOrderMap());
orderAdapter.notifyDataSetChanged();
txt_order_total.setText("Total Price: " + controller.calculateTotalPrice());
}
}
Picture of UI. (ListView on the right side is present on all the tabs and contains all the products in the order):
Don't ask for the arguments/extras in the constructor! They are not set at this time. They will be available later.
//If you create your Fragments yourself, create them in a static factory method:
public static Fragment newInstance(String productType){
Bundle b = new Bundle();
b.putString(ARG_PRODUCT_TYPE, productType);
Fragment f = new OrderFragment();
f.setArguments(b);
return f;
}
//Write a helper method for your arguments
public String getProductType(){
if(getArguments().containsKey(ARG_PRODUCT_TYPE)){
return getArguments().getString(ARG_PRODUCT_TYPE);
}
return null;
}
Then use the helper method after the Constructor, i.e. in onCreate().