I am using MPAndroidChart library to make charts for an android application. I would like to make 3-4 charts and want to swipe them. Is it possible to have swipe functionality using MPAndroidChart library and how can I implement such swipe function?
I think by understanding your problem I may suggest two possible ways to do so.
1] Use horizontal recycler view and each row will have a chart to show and to do so create a list with custom model class.
2] Use ViewPager with Fragment:
To create a view pager pass your expected list of graphs and on every getItem create a new Fragment instance and attach it to viewpager.
Pass custom model class as a input values to render your chart through bundle using parcable or serializable interface.
Each fragment will have a chart to show.
Use a ViewPager and attach a FragmentStatePagerAdapter
public class SomePagerAdapter extends FragmentStatePagerAdapter {
int mNumOfTabs;
public MISPagerAdapter(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new LineChartFragment();
case 1:
return new BarChartFragment();
case 2:
return new PieChartFragment();
default:
return null;
}
}
#Override
public int getCount() {
return mNumOfTabs;
}}
Each Fragment will have its own dataset using which the charts will be drawn.
Related
I already created this with custom adapter in another project, but I didn't use fragments. I now have a project using fragments, and am displaying the listview in a fragment. I don't know or am able to find exactly what rules and what classes/java files I need for this to work in a fragment.
Every example on the internet I've used develops an error in some way, and since I don't understand every aspect of how this is done I can't fix it on my own.
In my previous project, I did this (CalculationsActivity.java):
public class CalculationsActivity extends AppCompatActivity implements Serializable {
//content of my class
}
class CustomAdapter extends BaseAdapter {
#Override
public int getCount() {
return arrayLi.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
view = getLayoutInflater().inflate(R.layout.customlayout, null);
ImageView imageView = (ImageView) view.findViewById(R.id.imageView);
TextView content = (TextView) view.findViewById(R.id.content);
TextView date = (TextView) view.findViewById(R.id.date);
imageView.setImageResource(R.drawable.calcer);
String[] convertedArrLi = arrayLi.toArray(new String[arrayLi.size()]);
String[] convertedDates = dates.toArray(new String[dates.size()]);
content.setText(convertedArrLi[i]);
date.setText(convertedDates[i]);
return view;
}
}
And from that I set an adapter to my listview. This class was in the same java file as the activity that the listview was displayed in. If I do this in my fragment, I get a bunch of red lines. getLayoutInflater() and variables from my other class above it will be red.
As I understand so far you need MainActivity.java, MyFragment.java and Adapter.java. To make your listview work with your array you need to set an adapter including the current activity and the array you want to use. If someone can explain what files I actually need and how they work together (send info to each other and start one another), I would appreciate it.
Note: I have to use a custom adapter.
You can use your custom adapter in activity and in fragment, there is no difference. Can you provide screenshot of your bunch of red lines?
Also your question is incorrect: "what files do I need?". You need classes, first class for activity or fragment to create/declare/initialize second class (custom adapter) and fill it with data.
In my application I have two tabs, for which I am using ViewPager, two fragments are within this view pager. Sometimes when I tap on first tabs fragments EditBox keyboard pops, once I am done with the input keyboard disappears. But layout below keyboard region goes blank (White), this is happening sometimes, specially second launch of application. When application is launched from studio for first time issue doesn't appear. But when I launch it through system application by tapping on its ic_launhcher issue comes again. What are the possible causes of issue ?
The layout on launch looks like :
After I click on edit box & edit some text in address filed, when keyboard disappears, layout looks like :
I am using view pager inside another fragment & using FragmentStatePagerAdapter by passing a getChildFragmentManager()
private void setupViewPager(ViewPager viewPager) {
FragmentStatePagerAdapter fragmentStatePagerAdapter = new FragmentStatePagerAdapter(getChildFragmentManager()) {
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new GeneralInfoFragment();
Bundle bundle = new Bundle();
bundle.putString(context.getString(R.string.all_data), new Gson().toJson(profileResponse));
fragment.setArguments(bundle);
break;
case 1:
fragment = new ICEFragment();
break;
default:
return null;
}
return fragment;
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "General Info";
case 1:
return "ICE";
}
return "";
}
};
Note : Images are erased to protect privacy
Edit:
Put this code in your manifest file in your activity tag
android:configChanges="keyboard|keyboardHidden|orientation|
screenLayout|uiMode|screenSize|smallestScreenSize"
android:windowSoftInputMode="stateHidden|adjustPan"
Or
Try this one
setContentView(R.layout.activity_direction_3);
getWindow().getDecorView().setBackgroundColor(
android.R.color.transparent);
Or
if you have are using a custom theme then add this in your theme
<item name="android:windowBackground">Transparent color </item>
Tel me if you still get the issue.
I want to keep my application thin.
Problem: I would like to reuse my Fragment class code to create 3 different instances in the ViewPager which will have 3 pages. Each Fragment will have a different ImageView or background Drawable. What are best practices regarding this? I noticed that using factory methods like here seem to be good, any other alternatives?
I have one Fragment which has the following methods:
Fragment.java
public static Fragment newInstance(Context context) {
FragmentTutorial f = new FragmentTutorial();
Bundle args = new Bundle();
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment, null);
return root;
}
I have a ViewPagerAdapter class which has the following methods:
ViewPagerAdapter.java
public ViewPagerAdapter(Context context, FragmentManager fm) {
super(fm);
mContext = context;
}
#Override
public Fragment getItem(int position) {
return new FragmentTutorial().newInstance(mContext);
}
#Override
public int getCount() {
return totalPage;
}
What I've found is the "best" way to do it (in my opinion, of course) is to do the following:
Have the fragment contain methods to set the customizable data (background, text, etc)
Note: Be careful of trying to load the data in when first creating the fragment. You may be able to set the data before onCreateView() even runs, or at other times it may run after onCreateView(). I personally use a boolean to check if the data has been set. Inside onCreateView() [or onActivityCreated()], I check if the data has been set already. If it has, load in the data. Alternatively, while setting the data, I check if the views have been created/cached already. This is done by simply having variables to cache the data, say private ImageView mBackgroundView. If the view is not null, then I safely set the data on the views.
The above is also an alternative to using newInstance, although both methods work pretty well. However, for more flexibility, I only use newInstance if a) the data is already known before the fragment has to be inserted and b) the data doesn't need to change according to input from elsewhere much.
Let the ViewPager handle all the data
Pass in all the data - a list of ImageViews, a array of Strings, define where all the data is in Resources, etc - at the very beginning [say, in the constructor]
Have the ViewPager create an ArrayList of the fragments- set up each fragment as early as possible (say when first getting all the data) and add it to the list
Let getCount() just use the size of the list
Let getItem() just get the item in the list at the position
Note: If you have any dynamic data, set it up in the getItem() method. Furthermore, you can always add more data+fragments during runtime as well [just notify the adapter that the dataset has been changed]
Essentially, the fragment is like a simple servant- it does simply the least work necessary. If it doesn't have to handle choosing the data, all the better. It'll thus be far more flexible. Just give methods to set the data/views appropriately on the fragment. Now, the ArrayAdapter can do all the grimy hard work with managing the data and giving it to the appropriate fragment. Take advantage of that.
Now, note that this is assuming you want to use a single layout but want to change different aspects of that layout (texts, background, etc). If you want to make a master fragment class that can use any sort of defined layout, you can but note that it decreases the runtime flexibility (how can you change the text or background to something you get from the internet? You simply can't if you only can define and choose from pre-set layouts).
Either way, the ArrayAdapter should take care of all the different data while the fragment simply does as it's designed to do, in a more flexible manner preferably.
Edit:
Here is the project where I most recently implemented this sort of pattern. Note that it has far more to it, so I'll replace it with some not-so-pseudo pseudo-code in the morning/afternoon.
ViewPager [a bit sloppy with all the different things I was trying to do, including extending from a FragmentStatePagerAdapter without actually using any of the specific features of a StatePagerAdapter. In other words, I still need to work on the lifecycle implementations everywhere]
Fragment [Also may be a bit sloppy but shows the pattern still]
The object (actually another fragment) that uses the ViewPager [it's actually a "VerticalViewpager" from a library, but other than the animations and direction to change the current fragment, it's exactly the same- particularly code-wise]
Edit2:
Here is a more (if overly) simplified example of the pattern described above.
Disclaimer: The following code has absolutely no lifecycle management implementations and is older code that has been untouched since around August '14
Fragment simply allows the user of the fragment to set the background color and the text of the single TextView
Link to BaseFragment
Link to layout file
The adapter creates three instances of the fragment and sets the background color and text of each. Each fragment's text, color, and total fragments is hard coded.
Link to Activity+adapter
Link to layout file
Now, here are the exact relevant portions of the code:
BaseFragment
// Note: Found out later can extend normal Fragments but must use v13 adapter
public class BaseFragment extends android.support.v4.app.Fragment {
FrameLayout mMainLayout; // The parent layout
int mNewColor = 0; // The new bg color, set from activity
String mNewText = ""; // The new text, set from activity
TextView mMainText; // The only textview in this fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the fragment's layout
View view = inflater.inflate(R.layout.fragment_base,container,false);
// Save the textview for further editing
mMainText = (TextView) view.findViewById(R.id.textView);
// Save the framelayout to change background color later
mMainLayout = (FrameLayout) view.findViewById(R.id.mainLayout);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// If there is new text or color assigned, set em
if(mNewText != ""){
mMainText.setText(mNewText);
}
if(mNewColor != 0){
mMainLayout.setBackgroundColor(mNewColor);
}
}
#Override
public void onStart(){
super.onStart();
}
// Simply indicate to change the text of the fragment
public void changeText(String newText){
mNewText=newText;
}
// Simply indicate to change the background color of the fragment
public void changeBG(int color) {
// If no color was passed, then set background to white
if(color == 0)
{
mNewColor=getResources().getColor(R.color.white);
}
// else set the color to what was passed in
else{
mNewColor=color;
}
}
}
MyAdapter
class MyAdapter extends FragmentPagerAdapter{
// Three simple fragments
BaseFragment fragA;
BaseFragment fragB;
BaseFragment fragC;
public MyAdapter(FragmentManager fm) {
super(fm);
}
public void setFragments(Context c){
// Set up the simple base fragments
fragA = new BaseFragment();
fragB = new BaseFragment();
fragC = new BaseFragment();
Resources res = c.getResources();
fragA.changeText("This is Fragment A!");
fragB.changeText("This is Fragment B!");
fragC.changeText("This is Fragment C!");
fragA.changeBG(res.getColor(R.color.dev_blue));
fragB.changeBG(res.getColor(R.color.dev_green));
fragC.changeBG(res.getColor(R.color.dev_orange));
}
#Override
public Fragment getItem(int position) {
// TODO: Make this more efficient, use a list or such, also comment more
Fragment frag = null;
if(position == 0){
frag = fragA;
}
else if(position == 1){
frag = fragB;
}
else if(position == 2){
frag = fragC;
}
return frag;
}
#Override
public int getCount() {
return 3;
}
}
You need to pass some sort of id along with newInstance() while creating instance. And according to that id you can use if..else to choose layout file.
See my reference code below:
int id;
public static Fragment newInstance(Context context, int id) {
FragmentTutorial f = new FragmentTutorial();
Bundle args = new Bundle();
this.id = id;
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if(id == 1)
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment1, null);
else
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment2, null);
return root;
}
Can't you just introduce fields to the Fragment class to account for the variances in background, etc. and add them to its constructor? Then in getItem instantiate the Fragment class with different values depending on the value of position.
Let me explain first: my application is planed to use 3 activities with swipe navigation. I am using different sherlock action bar for each one of them.
But since it is not possible to swipe between activities, the only solution is to work with fragments. I implemented that, but I came across a problem: is it possible to customize action bar for each fragment? Because now I'm stuck only with one. I've Googled and every solution is based on a menu, but is it possible to apply custom styles to menus and in fragments?
Sorry if this was already answered, I haven't found any solution online.
Is it possible to use this kind of approach?
public class ControlActivity extends SherlockFragmentActivity {
ActionBar actionBar;
View actionBarView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewpager_layout);
ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
pager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));
actionBar = getSupportActionBar();
actionBarView= getLayoutInflater().inflate(
R.layout.friend_list_ab_layout, null);
actionBar.setCustomView(actionBarView);
}
private class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public SherlockFragment getItem(int pos) {
switch(pos) {
case 0:
actionBarView= getLayoutInflater().inflate(
R.layout.friend_list_ab_layout, null);
actionBar.setCustomView(actionBarView);
return MainActivity.newInstance();
case 1:
actionBarView= getLayoutInflater().inflate(
R.layout.news_feed_ab_layout, null);
actionBar.setCustomView(actionBarView);
return NewsFeed.newInstance();
default:
actionBarView= getLayoutInflater().inflate(
R.layout.friend_list_ab_layout, null);
actionBar.setCustomView(actionBarView);
return MainActivity.newInstance();
}
}
#Override
public int getCount() {
return 2;
}
}
}
well you can build your own action bar, what i mean to say is that you should create a dynamic fragment and use it at an action bar and give it styling a as action bar, use frame layout as a plcaeholder for the fragment and when you swipe the fragment replace the actionbar fragment with new one
Objective: To use fragment arguments to pass along the string value from a TextView to a new fragments TextView, BUT while using a ViewPager with different layouts/fragments in the FragmentPagerAdapter.
Problem: The new fragment never receives the fragments arguments from the previous fragment.
My Set up: I have my Activity hosting the ViewPager and FragmentPagerAdapter. I have overridden FragmentPagerAdapters getItem(int position) method to create a new fragment instance depending on the current position of the ViewPager. Right now I only have two Fragments in my adapter, but will be adding more after getting over this obstacle. I am using the newInstance() technique to pass along the Fragment's arguments, but nothing is ever passed.
Pertinent Code:
My FragmentPagerAdapter code:
//this is a variable that I pass in as the newInstanct() methods parameter,
// I update this variable from my fragments constantly
public static String fragmentArgumentsValue = "";
mViewPager.setAdapter(new FragmentPagerAdapter(fm) {
#Override
public int getCount() {
return NUMBER_OF_VIEWS;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
Log.d(TAG, "---In getPosition(), position 0---");
return Frag1
.newInstance(fragmentArgumentsValue);
case 1:
Log.d(TAG, "---In getPosition(), position 1---");
return frag2
.newInstance(fragmentArgumentsValue);
default:
Log.d(TAG, "---In getPosition(), DEFAULT---");
return frag1
.newInstance(fragmentArgumentsValue);
}
}
});
One of the fragments newInstance() method:
public static Fragment newInstance(String fragmentArgumentsValue) {
Frag1 f = new Frag1();
Bundle bun = new Bundle();
bun.putString(KEY_FRAGMENT_ARGUMENTS_STRING, fragmentArgumentsValue);
f.setArguments(bun);
return f;
}
Getting the fragments arguments:
String argString = getArguments().getString(
KEY_FRAGMENT_ARGUMENTS_STRING);
if (argString.length() != 0) {
Log.d(TAG, "Trying to set the frag args to:" + argString);
mWorkingTextView.setText("" + argString);
} else {
Log.d(TAG, "Couldn't set frag args to: " + argString);
}
What I've Tried: I've tried giving the Activity that hosts the ViewPager and FragmentPagerAdapter a static variable that I constantly update in each one of my fragments, I include the static variable in the fragment.newInstance(staticVariableInActivity) method, but this doesn't seem to work.
I've also tried using the ViewPager callback viewPager.setOnPageChangeListener() I had overridden the onPageSelected(int pos) and tried to pass the fragment arguments there, nevertheless it didn't work... so please help me S.O.!!!
My thoughts: I do not have the different fragments and layouts in an ArrayList or any list for that matter, I just instantiate the Fragments via the newInstance() method depending on the positions of the FragementPagerAdapter, could this be a problem? Should I create a singleton list of the layouts/fragments? So I can change the values of the Fragments TextViews via the singleton list? (excuse me if that's a dumb or not possible thing to do).
Note: I am am saving away the TextViews values via public void onSaveInstanceState(Bundle outState) to handle screen rotations. Could this be a problem?
Alright so I this link will help in the communication between fragments: Communication with other Fragments .
You need to define a interface that the Activity will implement and the fragments will use to send data onward to the activity, and the activity will then find the fragment by tag doing something like this:
frag = (Fragment2) getSupportFragmentManager()
.findFragmentByTag(
"android:switcher:" + R.id.viewPager + ":2");
and then update the fragment by calling a public method implemented within the fragment.
The link provided will help greatly, it is from the Android Development website.
Adds the bundle inside your Adapter.
example in the constructor of the adapter :
public ViewPagerAdapter(Context context, FragmentManager fm) {
super(fm);
fragments.add(TileFragments.newInstance());
Bundle bundleFeatures = new Bundle();
bundleFeatures.putString(ContentName.FEATURES.toString(),ContentName.FEATURES.toString());
fragments.get(0).setArguments(bundleFeatures);
}