My application uses a Multi Pane layout to display a list of assignments. Each Assignment can be put in one AssignmentCategory. I want to use a DrawerLayout to display all the AssignmentCategories so the user can switch easily between the diffirent categories.
I didn't manage to create such a layout. In the official DrawerLayout tutorial the DrawerLayoutActivity replaces a Fragment when a user clicks on a item (in my case an AssignmentCategory). The problem I facing is that a Multi Pane layout requires a FragmentActivity. I don't know how to create a Fragment which contains a Multi Pane layout. Did someone manage to do this?
Combining the two projects shouldn't be too difficult. In the sample code the DrawerLayout example does replace the content fragment but you don't have to do the same, you could simply update the same fragment to show the proper data. You could implement the two projects this way:
start from the multi pane demo project.
update the two activities of the multi pane demo to extends ActionBarActivity(v7), you don't need to extend FragmentActivity
implement the DrawerLayout(the sample code from the drawer project) code in the start list activity(I'm assuming you don't want the DrawerLayout in the details activity, but implementing it shouldn't be a problem if you want it).
the layout of the start list activity will be like this(don't forget that you need to implement the DrawerLayout changes in the activity_item_twopane.xml as well!):
<DrawerLayout>
<fragment android:id="#+id/item_list" .../>
<ListView /> <!-- the list in the DrawerLayout-->
</DrawerLayout>
change the implementation DrawerItemClickListener so when the user clicks the drawer list item you don't create and add a new list fragment, instead you update the single list fragment from the layout:
AssignmentListFragment alf = (AssignmentListFragment) getSupportFragmentManager()
.findFragmentById(R.id.item_list);
if (alf != null && alf.isInLayout()
&& alf.getCurrentDisplayedCategory() != position) {
alf.updateDataForCategory(position); // the update method
setTitle(DummyContent.CATEGORIES[alf.getCurrentDisplayedCategory()]);
}
the update method would be something like this:
/**
* This method update the fragment's adapter to show the data for the new
* category
*
* #param category
* the index in the DummyContent.CATEGORIES array pointing to the
* new category
*/
public void updateDataForCategory(int category) {
mCurCategory = category;
String categoryName = DummyContent.CATEGORIES[category];
List<DummyContent.Assigment> data = new ArrayList<Assigment>(
DummyContent.ITEM_MAP.get(categoryName));
mAdapter.clear(); // clear the old dsata and add the new one!
for (Assigment item : data) {
mAdapter.add(item);
}
}
public int getCurrentDisplayedCategory() {
return mCurCategory;
}
-various other small changes
I've made a sample project to illustrate the above changes that you can find here.
Related
I want to create a custom ListView.
Initially, the custom ListView has one array of data, but when user taps one of the list items, it's then removed from current array and added to another. If the user taps on the second array, the list item is then added back over into the first array.
Please suggest how to apply logic to do this.
Updates : I wants to use only one listview/recyclerview.
Following are screen shots..
Regarding the object switch - this is a simple transfer between lists, , just know beforehand if the insertion and removal is index based, e.g:
contacts.add(iLocation, ContactObject);
favorites.remove(iOtherLocation);
Regarding the ListView stuff, I would suggest converting to RecyclerView, let's build a general scenario:
You have a screen (Activity or Fragment) that holds one list (the implementation can be ListView or Recycler), and another screen that holds the other list.
In both of your lists you have adapters in which you implement the logic for the clicks on the objects in the lists.
The click transfers the object, either directly to the other list, OR to a temporary Object holder (because you might need it for other stuff), in which case you will need to pull that object from the other view, either way you remove it from the current one.
you switch to the other view, and refresh it.
An easy way to go -
Assuming the screens are the same, use only one Activity, holding a single RecyclerView, and handle 2 adapters, each for every list, the adapters allow you to handle the clicks easily, with an index for the object clicked, the click executes the info swap action,the Activity handles the visual swap Action.
a very general example would be:
//init everything obviously ;)
List<ContactObject> contacts;
List<ContactObject> favoritesContacts;
//the AdapteListener is an interface declared inside the adapter
mContactsRecyclerAdapter = new ContactsRecyclerAdapter(this, contacts,new ContactsRecyclerAdapter.AdapterListener()
{
#Override
public void cellClicked(int iIndex, ContactObject object)
{
favoritesContacts.add(iIndex, ContactObject);
contacts.remove(iIndex);
mContactsRecyclerAdapter.notifyDataSetChanged();
mFavoritesRecyclerAdapter.notifyDataSetChanged();
mRecyclerView.swapAdapter(mFavoritesRecyclerAdapter, false);
}
});
And vice-versa for the other adapter.
Hope this helps, comment if you have problems and I'll update.
Please implements with custom view extend with Linearlayout
Custom view has 2 child Linearlayout in which will add with this custom view
First time add all the element in first Linearlayout and based on user action please remove from first Linearlayout and add it in another layout
I have one fragment in which I'm generating an ArrayList. After the ArrayList is generated, I'm sending it to the Activity using interface
Inside my fragment-
public interface sendTheArraylist{
void ArrayList(ArrayList<Song> songArrayList);
}
And in the MainActivity-
#Override
public void accessArrayList(ArrayList<Song> songArrayList) {
this.queueArrayList=songArrayList;
queueAdapter =new SongAdapter(this,queueArrayList);
....
}
However, I see that whenever any changes are made in the queueArrayList in MainActivity, the songArrayList in the fragment is also getting affected. How can I stop the ArrayList in the Fragment from getting changed?
Try with the following.
this.queueArrayList.clear();
this.queueArrayList.addAll(songArrayList);
The reason is that you are referencing the arraylist to queueArrayList directly which also reflects changes back in songArrayList
Using an interface you pass the reference of that list so whenever you change that list will also affect on fragment list too. so the solution is rather than pass a reference to that list create one new list and make copy of it.
You can try and give a look at the Collections.copy method:
public static void copy(List dest, List src)
Copies all of the elements from one list into another. After the operation, the index of each copied element in the destination list will be identical to its index in the source list. The destination list must be at least as long as the source list. If it is longer, the remaining elements in the destination list are unaffected. This method runs in linear time.
Parameters: dest - The destination list. src - The source list.
hope it will help you.
Here is the complete solution:
before calling sendTheArraylist Inside your fragment-
ArrayList<Song> songArrayListToPass= new ArrayList<Song>(songArrayList.size());
Collections.copy(songArrayListToPass, songArrayList);
YourActivityRef.sendTheArraylist(songArrayListToPass);
This way your any update on your songArrayListToPass inside Activity will not reflect in Fragment.
I've got a TabLayout (from the Design Library) that is populated with 2 fragments (that both hold a list of items) through a FragmentPagerAdapter.
The 2 lists are in connection with each other: They both hold a total of persons and in which list a person is, decides whether he/she is nominated or not.
You can swipe members from one list to the other and vice versa.
The problem
I want/need to show a count (of how many persons are in that particular list) in the tab titles.
Easy enough, I add a bit of code in getPageTitle and it works fine.
Until I change the lists, and I need to tell the FragmentPagerAdapter to update its titles again: It won't.
So far, the only solution I found was to call: mTabLayout.setTabsFromPagerAdapter(mAdapter);
All this method does, is removeAllTabs and then loop through the ones the FragmentPagerAdapter has, adding them as new.
This works for the titles, but isn't very efficient, but most importantly: It forces the first tab to become the selected item again, which isn't a nice experience when swiping from the 2nd tab.
I've tried adding mViewPager.setCurrentItem(int item) after the mTabLayout.setTabsFromPagerAdapter(mAdapter); call, but that does not work.
I also tried things like
mAdapter.notifyDataSetChanged();
tabLayout.invalidate();
With no effect.
Here is how i am doing, I had requirement in which i need to set some count to tab title everytime.
I used custom layout for tab title. here is my custom_tab layout
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/tab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/colorAccent"
android:textSize="#dimen/tab_label" />
TO setup title first time i use my method setupTabTitle("TAB 1",0);
private void setupTabTitle(String title,int pos) {
TextView title = (TextView) LayoutInflater.from(this).
inflate(R.layout.custom_tab, null);
title .setText(title);
// set icon
// title .setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.ic_tab_favourite, 0, 0);
tabLayout.getTabAt(pos).setCustomView(title);
}
To update tab-title next time i use tabLayout.getTabAt() object
public void updateCustomTabTitle(String title,int pos) {
TextView tabTitle = (TextView) tabLayout.getTabAt(pos).getCustomView();
tabTitle.setText(title);
}
and this is how i call updateCustomTabTitle method
updateCustomTabTitle("My tab title to update",tabLayout.getSelectedTabPosition());
To get tab-title value
public String getCustomTabTitle(int pos) {
TextView tabOne= (TextView) tabLayout.getTabAt(pos).getCustomView();
return tabOne.getText().toString();
}
note: first i tried setupTabTitle method to update tab-title but it does not update title, it append new text at end of title. so i get View from tab-layout and use it to update and read tab value.
Hope this will help you.
I play arround with the SlidingTabsColors example from the android developers site. Where can I add a different content fragment? Now all tabs have the same fragment/layout. I tried to copy all important for the content fragment and renamed it, changed the fragment and the layout. But it dont works this way. Probably the ArrayList is not the best for different content?
I am not sure whether I got the question right but the fact is that there are fragments created in
SlidingTabsColorsFragment.java by the following method:
Fragment createFragment() {
return ContentFragment.newInstance(mTitle, mIndicatorColor, mDividerColor);
}
So I would suggest to simply change that method to something like this:
Fragment createFragment() {
return MyVeryOwnFragment.newInstance(mTitle, mIndicatorColor, mDividerColor);
}
Because there can only be Fragments displayed whose were created beforehand in this method. Then your own Fragment will be displayed in the content area.
You may also want to watch this video on the topic by the android developers youtube channel.
-------- Edit --------
Ok so the question was how to insert multiple different fragments:
Fragment createFragment() {
// Decide based on a class member which Fragment should be created.
Fragment frament;
if (mIndicatorColor == Color.Red) {
fragment = new MyRedFragment(mTitle, mDividerColor);
} else if (mIndicatorColor == Color.Blue) {
fragment = new MyBlueFragment(mTitle, mDividerColor);
}
return fragment;
}
You may want to introduce a different memeber than color. That could be an enum field.
Target MvvmCross, Android
Objective: A screen (ViewModel/View) where the user can select an animal group (Amphibians, Birds, Fish, Invertebrates, Mammals, Reptiles). When a group has been selected, a Fragment Views will will display information for that animal group. The fields and layout differ per animal group (e.g. fish don't have wings).
Although for this question I have chosen for animal group (which is pretty static), want the list animal groups to be flexible.
Simplified app structure:
MyApp.Core
ViewModels
MainViewModel
IAnimalGroupViewModel
AmphibiansViewModel
BirdsBViewModel
FishViewModel
MyApp.Droid
Layout
MainView
AmphibiansFragment
BirdsFragment
FishFragment
Views
MainView
AmphibiansFragment
BirdsFragment
FishFragment
The MainView.axml layout file will contain (a placeholder for) the fragment of the displayed animal group.
In WPF or WP8 app I could make use of a ContentPresenter and a Style to automatically display the selected ViewModel with its View.
How could I achieve something like that in Droid?
I could use a Switch/Case in the MainView.cs that sets the Fragment according to the type of the selected ViewGroup. But that means I have to modify the MainView every time I add a new View.
Any suggestions/ideas?
Currently MvvmCross doesn't provide any kind of automatic navigation mechanism for Fragments in the same way that it does for Activities.
However, within your use case, if you wanted to use a navigation approach, then you could automatically build a similar type of automated lookup/navigation mechanism.
To do this, the easiest developer root would probably be to use reflection to find a lookup dictionary for all the fragments
var fragments = from type in this.GetType().Assembly.GetTypes()
where typeof(IAnimalGroupView)..sAssignableFrom(type)
where type.Name.EndsWith("Fragment")
select type;
var lookup = fragments.ToDictionary(
x => x.Name.Substring(0, x.Name.Length - "Fragment".Length)
+ "ViewModel",
x => x);
With this in place, you could then create the fragments when they are needed - e.g.
assuming that you convert the Selection event via an ICommand on the ViewModel into a ShowViewModel<TViewModel> call
and assuming that you have a Custom Mvx presenter which intercepts these ShowViewModel requests and passes them to the activity (similar to the Fragment sample) - e.g.
public class CustomPresenter
: MvxAndroidViewPresenter
{
// how this gets set/cleared is up to you - possibly from `OnResume`/`OnPause` calls within your activities.
public IAnimalHostActivity AnimalHost { get; set; }
public override void Show(MvxViewModelRequest request)
{
if (AnimalHost != null && AnimalHost.Show(request))
return;
base.Show(request);
}
}
then your activity could implement Show using something like:
if (!lookup.ContainsKey(request.ViewModelType.Name))
return false;
var fragmentType = lookup[request.ViewModelType.Name];
var fragment = (IMvxFragmentView)Activator.Create(fragmentType);
fragment.LoadViewModelFrom(request);
var t = SupportFragmentManager.BeginTransaction();
t.Replace(Resource.Id.my_selected_fragment_holder, fragment);
t.Commit();
return true;
Notes:
if you aren't using ShowViewModel here then obviously this same approach could be adjusted... but this answer had to propose something...
in a larger multipage app, you would probably look to make this IAnimalHostActivity mechanism much more generic and use it in several places.