I'm making a simple flashcard app using a ViewPager, FragmentStatePagerAdapter, and some card flipping animations found on the offical Android tutorials (https://developer.android.com/training/animation/cardflip.html). I've created a shuffle button which shuffles the cards in the deck and then calls notifyDataSetChanged on the adapter to update the card views. Once called, it successfully updates the views, but it also creates a shadow/border around each card that doesn't clear until the card is touched and flipped.
When initially launched, the cards are basically have no border.
Here is what the cards look like after I spam the shuffle button. The border darkens on every press:
Here are some snippets of the relevant parts of my code:
MainAcivity.java
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.shuffleButton:
pager.removeAllViews();
pagerAdapter.shuffle();
pager.setAdapter(pagerAdapter);
}
return true;
CardPagerAdapter.java
public class CardPagerAdapter extends FragmentStatePagerAdapter {
public static final String CARD = "CARD";
private static final float WIDTH_SCALE = 0.95f;
private int count;
private Deck deck;
private ArrayList<Card> cards;
private boolean isShuffled;
public CardPagerAdapter(FragmentManager fragmentManager, Deck deck) {
super(fragmentManager);
this.deck = deck;
this.count = deck.getSize();
this.cards = deck.getCards();
this.isShuffled = false;
}
#Override
public Fragment getItem(int position) {
CardContainerFragment cardContainerFragment = new
CardContainerFragment();
Bundle bundle = new Bundle();
bundle.putParcelable(CARD, cards.get(position));
cardContainerFragment.setArguments(bundle);
return cardContainerFragment;
}
#Override
public int getItemPosition(Object item) {
return POSITION_NONE;
}
#Override
public int getCount() {
return count;
}
/**
* Override the pageWidth in order to be able
* to see other cards on the side of the current card.
* #param position The position of the current card
* #return The multiplier by which to change the width by
*/
#Override
public float getPageWidth(int position) {
return WIDTH_SCALE;
}
public void shuffle() {
if (isShuffled) {
cards = deck.getCards();
} else {
Collections.shuffle(cards);
}
isShuffled = !isShuffled;
notifyDataSetChanged();
}
}
CardContainerFragment.java
public class CardContainerFragment extends Fragment {
public static final String FLIPPED = "FLIPPED";
private static final float DISTANCE = 8000;
private CardFragment frontCardFragment;
private CardFragment backCardFragment;
private boolean cardFlipped;
public CardContainerFragment() {
setHasOptionsMenu(true);
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
// Create the card fragment view
final View rootView = inflater.inflate(
R.layout.card_fragment, container, false);
this.cardFlipped = false;
Bundle bundle = this.getArguments();
// Make the front and back cards
Bundle frontBundle = (Bundle) bundle.clone();
Bundle backBundle = (Bundle) bundle.clone() ;
frontCardFragment = new CardFragment();
frontBundle.putByte(FLIPPED, (byte) 0);
frontCardFragment.setArguments(frontBundle);
backCardFragment = new CardFragment();
backBundle.putByte(FLIPPED, (byte) 1);
backCardFragment.setArguments(backBundle);
// Set the first viewed fragment to be the the front of the card
getChildFragmentManager()
.beginTransaction()
.add(R.id.container, frontCardFragment)
.commit();
// Flip the card once touched
rootView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
flipCard();
}
});
return rootView;
}
/**
* Swaps the visible fragment with the other fragment (the other side of
the card)
* Animates the transition between the change with a flip animation.
*/
public void flipCard() {
Fragment fragment;
if (cardFlipped) {
fragment = frontCardFragment;
} else {
fragment = backCardFragment;
}
getChildFragmentManager()
.beginTransaction()
.setCustomAnimations(
R.animator.card_flip_left_in,
R.animator.card_flip_left_out,
R.animator.card_flip_right_in,
R.animator.card_flip_right_out)
.replace(R.id.container, fragment)
.commit();
cardFlipped = !cardFlipped;
}
public static class CardFragment extends Fragment {
private TextView cardText;
private ImageButton starButton;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup
container,
Bundle savedInstanceState) {
// Create the card fragment view and get the card object
View view = inflater.inflate(R.layout.card_view, container,
false);
Bundle bundle = this.getArguments();
final Card card = bundle.getParcelable(CardPagerAdapter.CARD);
boolean cardFlipped = bundle.getByte(FLIPPED) != 0;
// Change camera perspective to not have the flip animation be
// distorted
float scale = getResources().getDisplayMetrics().density;
view.setCameraDistance(DISTANCE * scale);
// Set the text from the card to the fragment's textview
cardText = (TextView) view.findViewById(R.id.cardText);
if (cardFlipped) {
cardText.setText(card.getBackText());
} else {
cardText.setText(card.getFrontText());
}
// Make the star button and set it based on if the card is
// starred
starButton = (ImageButton) view.findViewById(R.id.starButton);
if (card.isStarred()) {
starButton.setImageResource(R.mipmap.ic_star_white_48dp);
} else {
starButton.setImageResource(R.mipmap.ic_star_border_black_48dp);
}
starButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!card.isStarred()) {
starButton.setImageResource(R.mipmap.ic_star_white_48dp);
} else {
starButton.setImageResource(R.mipmap.ic_star_border_black_48dp);
}
card.toggleStarred();
}
});
return view;
}
}
}
Any help at all would be appreciated.
*EDIT
As requested here is the XML
card_fragment.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:stateListAnimator="#null">
</FrameLayout>
card_view.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:stateListAnimator="#null">
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:cardUseCompatPadding="true"
android:stateListAnimator="#null">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/cardText"
android:layout_width="350dp"
android:layout_height="500dp"
android:gravity="center"
android:text="This is the card contents."
android:textAlignment="center"
android:textSize="24sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintBottom_toBottomOf="parent" />
<ImageButton
android:id="#+id/starButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:background="#android:color/transparent"
android:tint="#android:color/darker_gray"
app:layout_constraintRight_toRightOf="#+id/cardText"
app:layout_constraintTop_toTopOf="#+id/cardText"
app:srcCompat="#mipmap/ic_star_border_black_48dp" />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
</FrameLayout>
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#d3d3d3"
tools:context="com.benvo.viewpager.activities.MainActivity">
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<ProgressBar
android:id="#+id/deckProgressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
Related
I have a fragment named "Notification fragment" in which I want to show another fragment named "Watching Fragment" using Tab layout . When I run the app, the tab layout bar is visible but the fragments are not visible.
My Fragment inside which other fragments are to be shown (Notifications Fragment)
public class NotificationsFragment extends Fragment{
GridView listv;
FragmentAdapter fragmentAdapter;
private NotificationsViewModel notificationsViewModel;
private FragmentNotificationsBinding binding;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
notificationsViewModel =
new ViewModelProvider(this).get(NotificationsViewModel.class);
binding = FragmentNotificationsBinding.inflate(inflater, container, false);
View root = binding.getRoot();
TabLayout tabLayout = root.findViewById(R.id.tabLayout);
ViewPager vp = root.findViewById(R.id.vp2);
fragmentAdapter = new FragmentAdapter(getChildFragmentManager() , tabLayout.getTabCount());
vp.setAdapter(fragmentAdapter);
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
vp.setCurrentItem(tab.getPosition());
if(tab.getPosition() == 0 || tab.getPosition() == 1 || tab.getPosition() == 2)
fragmentAdapter.notifyDataSetChanged();
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
vp.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
return root; }
My First Fragment (Watching Fragment)
public class WatchingFragment extends Fragment {
ArrayList<String> list = new ArrayList<String>();
GridView gridv1;
private WatchingViewModel mViewModel;
public static WatchingFragment newInstance() {
return new WatchingFragment();
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.watching_fragment, container, false);
gridv1 = view.findViewById(R.id.gridv1);
Intent intent = getActivity().getIntent();
String animename = intent.getStringExtra("nameanime");
list.add(animename);
loadData2();
saveData2();
ListNewAdapter adapter = new ListNewAdapter(getContext(), R.layout.watch_list, list);
gridv1.setAdapter(adapter);
gridv1.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
list.remove(position);
adapter.notifyDataSetChanged();
saveData2();
return true;
}
});
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel = new ViewModelProvider(this).get(WatchingViewModel.class);
// TODO: Use the ViewModel
}
private void saveData2() {
SharedPreferences sp = getActivity().getSharedPreferences("shared preferences", MODE_PRIVATE);
SharedPreferences.Editor ed = sp.edit();
Gson gson = new Gson();
String json = gson.toJson(list);
ed.putString("anime list", json);
ed.apply();
}
private void loadData2() {
SharedPreferences sp = getActivity().getSharedPreferences("shared preferences", MODE_PRIVATE);
Gson gson = new Gson();
String json = sp.getString("anime list", "");
Type type = new TypeToken<ArrayList<String>>() {}.getType();
list = gson.fromJson(json , type);
if (list == null) {
list = new ArrayList<String>();
}
}
}
My View pager adapter
public class FragmentAdapter extends FragmentPagerAdapter {
int tabcount;
public FragmentAdapter(#NonNull #NotNull FragmentManager fm, int behavior) {
super(fm, behavior);
tabcount = behavior;
}
#NonNull
#NotNull
#Override
public Fragment getItem(int position) {
switch (position){
case 0: return new WatchingFragment();
case 1: return new CompletedFragment();
case 2: return new WantToWatchFragment();
default: return null;
}
}
#Override
public int getCount() {
return 0;
}
}
Notifications Fragment Layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.notifications.NotificationsFragment">
<com.google.android.material.tabs.TabLayout
android:id="#+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Watching" />
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Completed" />
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Want To Watch" />
</com.google.android.material.tabs.TabLayout>
<androidx.viewpager.widget.ViewPager
android:id="#+id/vp2"
android:name="com.example.animeguide.ui.notifications.NotificationsFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tabLayout" />
</androidx.constraintlayout.widget.ConstraintLayout>
Watching Fragment Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.notifications.FragmentsInsideList.watching.WatchingFragment">
<TextView
android:id="#+id/textView4"
android:layout_width="184dp"
android:layout_height="58dp"
android:text="hello world"
android:textSize="34sp" />
<GridView
android:id="#+id/gridv1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="2" />
</LinearLayout>
In order for the Adapter to know how many pages it has, you need to override getCount method. You did override it, but used 0 as the number of pages, thus having no pages.
In your FragmentAdapter class, try changing this:
#Override
public int getCount() {
return 0;
}
To this:
#Override
public int getCount() {
return tabcount;
}
I want to use an expandableRecyler but when i use the adapter it doesnt work. It doesnt give me any error or anything. just doesnt appear on the screen
I have this Fragment where i call the recyclerView
public class RecFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
Button btaddrec;
Dialog alerta;
View v;
RecyclerView rvRec;
public RecFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment RecFragment.
*/
// TODO: Rename and change types and number of parameters
public static RecFragment newInstance(String param1, String param2) {
RecFragment fragment = new RecFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.fragment_rec, container, false);
rvRec = v.findViewById(R.id.recyclerviewRec);
btaddrec = (Button) v.findViewById(R.id.btaddRec);
initData();
setRecycler();
btaddrec.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getContext(), MainActivity.listarec.size() + "", Toast.LENGTH_SHORT).show();
}
});
return v;
}
private void setRecycler(){
RecyclerRec recyclerRec = new RecyclerRec(MainActivity.listarec);
rvRec.setLayoutManager(new LinearLayoutManager(getActivity()));
rvRec.setAdapter(recyclerRec);
rvRec.setHasFixedSize(true);
}
private void initData(){
MainActivity.listarec.add(new Recordatorio("Homework","Math and Science Homewowk","14:00"));
MainActivity.listarec.add(new Recordatorio("Homework","Math and Science Homewowk","14:00"));
}
}
Function initData add some objects to my list (i have checked that it works with the Button, my list has 2 items)
Function setRecycler set the adapter for the recyclerview
This is my class RecyclerRec
public class RecyclerRec extends RecyclerView.Adapter<RecyclerRec.RecVh>{
ArrayList<Recordatorio> listarec;
public RecyclerRec (ArrayList<Recordatorio> lista){
this.listarec = lista;
}
#NonNull
#Override
public RecVh onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_rec_layout,parent,false);
return new RecVh(v);
}
#Override
public void onBindViewHolder(#NonNull RecVh holder, int position) {
Recordatorio rec = listarec.get(position);
holder.tvTitulo.setText(rec.getTitulo());
holder.tvCuerpo.setText(rec.getCuerpo());
holder.tvHora.setText(rec.getHora());
boolean expanded = rec.isExpanded();
holder.expandable.setVisibility(expanded ? View.VISIBLE : View.GONE);
}
#Override
public int getItemCount() {
return listarec.size();
}
public class RecVh extends RecyclerView.ViewHolder {
TextView tvTitulo,tvCuerpo,tvHora;
LinearLayout linearLayout;
ConstraintLayout expandable;
public RecVh(#NonNull View itemView) {
super(itemView);
tvTitulo = itemView.findViewById(R.id.tvTituloRec);
tvCuerpo = itemView.findViewById(R.id.tvCuerpo);
tvHora = itemView.findViewById(R.id.tvHoraRec);
linearLayout = itemView.findViewById(R.id.linearlayotuexpand);
expandable = itemView.findViewById(R.id.expandableRec);
linearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Recordatorio rec = listarec.get(getAdapterPosition());
rec.setExpanded(!rec.isExpanded());
notifyItemChanged(getAdapterPosition());
}
});
}
}
}
XML of fragment
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Fragments.ClasesFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerviewRec"
android:layout_width="match_parent"
android:layout_height="451dp"
android:layout_marginTop="50dp" />
<Button
android:id="#+id/btaddRec"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="160dp"
android:layout_marginTop="520dp"
android:text="AƱadir" />
(Framelayout tag is closed correctly, dunno why stackoverflow doesnt write it with ctrl+k)
XML of my item/row
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:id="#+id/tvTituloRec"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="10dp"
android:text="Titulo Recordatorio"
android:textAppearance="#style/TextAppearance.AppCompat.Medium"
android:textColor="#android:color/black"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/tvHoraRec"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hora"
android:textSize="17dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/expandableRec"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tvTituloRec">
<TextView
android:id="#+id/tvCuerpo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:text="Cuerpo del recordatorio"
android:textAppearance="#style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toEndOf="#+id/textView"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
All seems to be in order but when i run the app it doesnt appear and doesnt give me any error.
In my RecyclerView I need replace part of my item to my fragment. But replacing only first item in recycler view. What I am doing is wrong?
My container (in recycler view item):
...
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/container" />
...
My update code in RecyclerView adapter:
...
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
...
MyFragment fragment = MyFragment.newInstance("fragment1");
fragmentManager.beginTransaction().replace(R.id.container, fragment).commit();
...
}
...
I finnaly found solution. The problem is I set a common container id. But in recycler view need to set unique container id for each item.
So, my code now this:
MyFragment fragment = MyFragment.newInstance("fragment1");
fragmentManager.beginTransaction().replace(UNIQUE_CONTAINER_ID, fragment).commit();
If someone will be useful, here is my complete code (implementation fragment in recycler view):
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
...
// Delete old fragment
int containerId = holder.mediaContainer.getId();// Get container id
Fragment oldFragment = fragmentManager.findFragmentById(containerId);
if(oldFragment != null) {
fragmentManager.beginTransaction().remove(oldFragment).commit();
}
int newContainerId = View.generateViewId();// Generate unique container id
holder.mediaContainer.setId(newContainerId);// Set container id
// Add new fragment
MyFragment fragment = MyFragment.newInstance("fragment1");
fragmentManager.beginTransaction().replace(newContainerId, fragment).commit();
...
}
Upd.: Instead of using your own method to generate a unique id, it is recommended to use View.generateViewId()
Thanks to Mikhali, I'm able to provide to you a complete running example.
Pay special attention on the comments in onBindViewHolder()
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewLedgerAdapter.ViewHolder>{
private final String TAG = RecyclerViewAdapter.class.getSimpleName();
private final float FINAL_OPACITY = 0.3f;
private final float START_OPACITY = 1f;
private final int ANIMATION_TIME = 500;
private final int TYPE_ITEM = 0;
private final int TYPE_DATE = 1;
private final int TYPE_TRANSACTION = 2;
private final int TYPE_PENDING = 3;
private HashMap<Integer, Integer> mElementTypes;
private List<Operation> mObjects;
private Context mContext;
private Utils.CURRENCIES mCurrencySelected; // Which currency is already selected
private boolean mCurrencyFilter; // Defines if a currency is already selected to apply filter
private Animation mAnimationUp;
private Animation mAnimationDown;
public RecyclerViewLedgerAdapter(List<Operation> objects, Context context) {
mElementTypes = new HashMap<Integer, Integer>();
mObjects = objects;
mContext = context;
mCurrencyFilter = false;
mCurrencySelected = null;
mAnimationUp = AnimationUtils.loadAnimation(context, R.anim.slide_up);
mAnimationDown = AnimationUtils.loadAnimation(context, R.anim.slide_down);
}
...
...
Not needed methods
...
...
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_element_ledger, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
Operation operation = mObjects.get(position);
holder.setAppUserActivity(userActivityOperation);
// Remember that RecyclerView does not have onClickListener, you should implement it
holder.getView().setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Hide details
// iDetailsContainer object could be checked on inner class ViewHolder
if(holder.iDetailsContainer.isShown()){
holder.iDetailsContainer.setVisibility(View.GONE);
}else{
// Show details
// Get fragment manager inside our fragment
FragmentManager fragmentManager = ((UserActivity)mContext).getSupportFragmentManager();
// Delete previous added fragment
int currentContainerId = holder.iDetailsContainer.getId();
// Get the current fragment
Fragment oldFragment = fragmentManager.findFragmentById(currentContainerId);
if(oldFragment != null) {
// Delete fragmet from ui, do not forget commit() otherwise no action
// is going to be observed
ragmentManager.beginTransaction().remove(oldFragment).commit();
}
// In order to be able of replacing a fragment on a recycler view
// the target container should always have a different id ALWAYS
int newContainerId = getUniqueId();
// Set the new Id to our know fragment container
holder.iDetailsContainer.setId(newContainerId);
// Just for Testing we are going to create a new fragment according
// if the view position is pair one fragment type is created, if not
// a different one is used
Fragment f;
if(position%2 == 0) {
f = new FragmentCard();
}else{
f=new FragmentChat();
}
// Then just replace the recycler view fragment as usually
manager.beginTransaction().replace(newContainerId, f).commit();
// Once all fragment replacement is done we can show the hidden container
holder.iDetailsContainer.setVisibility(View.VISIBLE);
}
}
// Method that could us an unique id
public int getUniqueId(){
return (int)SystemClock.currentThreadTimeMillis();
}
});
}
public class ViewHolder extends RecyclerView.ViewHolder{
private View iView;
private LinearLayout iContainer;
public LinearLayout iDetailsContainer;
private ImageView iOperationIcon;
private ImageView iOperationActionImage;
private TextView iOperation;
private TextView iAmount;
private TextView iTimestamp;
private TextView iStatus;
private UserActivityOperation mUserActivityOperation;
public ViewHolder(View itemView) {
super(itemView);
iView = itemView;
iContainer = (LinearLayout) iView.findViewById(R.id.operation_container);
iDetailsContainer = (LinearLayout) iView.findViewById(R.id.details_container);
iOperationIcon = (ImageView) iView.findViewById(R.id.ledgerOperationIcon);
iOperationActionImage = (ImageView) iView.findViewById(R.id.ledgerAction);
iOperation = (TextView) iView.findViewById(R.id.ledgerOperationDescription);
iAmount = (TextView) iView.findViewById(R.id.ledgerOperationCurrencyAmount);
iTimestamp = (TextView) iView.findViewById(R.id.ledgerOperationTimestamp);
iStatus = (TextView) iView.findViewById(R.id.ledgerOperationStatus);
// This linear layout status is GONE in order to avoid the view to use space
// even when it is not seen, when any element selected the Adapter will manage the
// behavior for showing the layout - container
iDetailsContainer.setVisibility(View.GONE);
}
...
...
Not needed methods
...
...
}
}
Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/operation_container_maximum"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="11dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginTop="11dp"
android:orientation="vertical">
<LinearLayout
android:id="#+id/operation_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="14dp">
<ImageView
android:id="#+id/ledgerOperationIcon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="#drawable/fondear" />
<ImageView
android:id="#+id/ledgerAction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:src="#drawable/operation_trade" />
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:weightSum="2">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:id="#+id/ledgerOperationDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Descripcion"
android:textColor="#color/ledger_desc" />
<TextView
android:id="#+id/ledgerOperationCurrencyAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="2dp"
android:text="5000 BTC" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:id="#+id/ledgerOperationTimestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Fecha/Hora"
android:textColor="#color/ledger_timestamp" />
<TextView
android:id="#+id/ledgerOperationStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Status" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="#+id/details_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Something hidden" />
<ImageView
android:layout_marginTop="15dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/user_btc"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
</LinearLayout>
Fragment
// This is one of the fragments used in the RecyclerViewAdapterCode, and also makes a HTTPRequest to fill the
// view dynamically, you could laso use any of your fragments.
public class FragmentCard extends Fragment {
TextView mTextView;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_card, container, false);
mTextView = (TextView) view.findViewById(R.id.tv_fragment_two);
new UserActivityAsyncTask().execute();
return view;
}
private UserActivityOperation[] asyncMethodGetPendingWithdrawals(){
BitsoWithdrawal[] userWithdrawals = HttpHandler.getUserWithdrawals(getActivity());
int totalWithDrawals = userWithdrawals.length;
UserActivityOperation[] appUserActivities = new UserActivityOperation[totalWithDrawals];
for(int i=0; i<totalWithDrawals; i++){
appUserActivities[i] = new UserActivityOperation(userWithdrawals[i], getActivity());
}
return appUserActivities;
}
private class UserActivityAsyncTask extends AsyncTask<String, Void, Integer> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Integer doInBackground(String... strings) {
// Precess Compound balance
UserActivityOperation[] compoundBalanceProcessed = asyncMethodGetPendingWithdrawals();
return compoundBalanceProcessed.length;
}
#Override
protected void onPostExecute(Integer result) {
super.onPostExecute(result);
mTextView.setText(result.toString());
}
}
}
and thank you for stopping by.
I've been facing a weird behavior using the combination of both PageTransformer and TransitionManager.
The hierarchy I'm using is fairly easy : A viewPager with each page being a fragment. The fragment has two different layouts, changing with the TransitionManager.go().
The issue :
If I just scroll through the viewPager, everything is fine, and my pageTransformer applies the right values, creating the desired parallax effect.
If I just click back and forth to change scenes inside a page, I also get the desired output.
However, whenever I use the TransitionManager.go() (let's say twice, to go back to the first layout) and then start scrolling through my viewPager, the parallax effect doesn't occur anymore.
My question :
Is there any known issue I haven't been able to find with using both a PageTransformer and a TransitionManager at the same time?
My code :
Fragment1.java
public class Fragment1 extends Fragment {
private Scene mStartScene;
private Scene mInfoScene;
private Transition mTransition;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.view_pager_item_default, container, false);
RelativeLayout rootLayout = (RelativeLayout) v.findViewById(R.id.p1);
mTransition = new ChangeBounds();
mTransition.setDuration(400);
mStartScene = Scene.getSceneForLayout(rootLayout, R.layout.view_pager_item_default, getContext());
mInfoScene = Scene.getSceneForLayout(rootLayout, R.layout.view_pager_item_details, getContext());
return (v);
}
public void changeScene(View v) {
Scene tmp = mInfoScene;
mInfoScene = mStartScene;
mStartScene = tmp;
TransitionManager.go(mStartScene, mTransition);
}
}
view_pager_item_default.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/p1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView"
android:elevation="20dp"
android:text="Item 1"
android:onClick="changeScene"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="60dp"
android:layout_width="match_parent"
android:layout_alignParentBottom="true"
android:padding="20dp"
android:layout_height="wrap_content"
android:background="#drawable/white_shape"
android:textSize="40sp"
android:gravity="center"
android:textColor="#000000"/>
<ImageView
android:id="#+id/imageView"
android:elevation="19dp"
android:scaleType="centerCrop"
android:layout_marginBottom="-10dp"
android:layout_centerHorizontal="true"
android:src="#mipmap/big_image"
android:background="#android:color/transparent"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
view_pager_item_details.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/p1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView"
android:elevation="20dp"
android:text="Item 1 description"
android:onClick="changeScene"
android:layout_marginTop="150dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="20dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/white_shape"
android:clickable="true"
android:textSize="30sp"
android:gravity="center"
android:textColor="#000000"/>
<ImageView
android:id="#+id/imageView"
android:elevation="21dp"
android:layout_marginTop="50dp"
android:layout_centerHorizontal="true"
android:src="#mipmap/small_image"
android:background="#android:color/transparent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
My adapter is fairly simple :
public class MyPagerAdapter extends FragmentPagerAdapter {
private final List fragments;
public MyPagerAdapter(FragmentManager fm, List fragments) {
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int position) {
return (Fragment) this.fragments.get(position);
}
#Override
public int getCount() {
return this.fragments.size();
}
}
Then is my PageTransformer which moves each children of the view independently
public class MyPagerTransformer implements ViewPager.PageTransformer {
private float mParallaxCoeff;
private float mDistanceCoeff;
public MyPagerTransformer(float parallax, float distance) {
mParallaxCoeff = parallax;
mDistanceCoeff = distance;
}
#Override
public void transformPage(View page, float position) {
float coefficient = page.getWidth() * mParallaxCoeff;
ViewGroup vG = (ViewGroup) page;
for (int i = vG.getChildCount() - 1; i >= 0; --i) {
View v = vG.getChildAt(i);
if (v != null) {
v.setTranslationX(coefficient * (position * position * position));
}
coefficient *= mDistanceCoeff;
}
}
}
And lastly my Activity :
public class MainActivity extends AppCompatActivity {
private Fragment1 mFrag1;
private Fragment1 mFrag2;
private Fragment1 mFrag3;
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
mViewPager = (ViewPager) findViewById(R.id.main_view_pager);
CirclePageIndicator indicator = (CirclePageIndicator) findViewById(R.id.indicator);
if (mViewPager != null) {
mViewPager.setPageTransformer(true, new MyPagerTransformer(8.0f, 8.0f));
//vp.addOnPageChangeListener(listener);
List<Fragment> fragments = new ArrayList<>();
mFrag1 = new Fragment1();
mFrag2 = new Fragment1();
mFrag3 = new Fragment1();
fragments.add(mFrag1);
fragments.add(mFrag2);
fragments.add(mFrag3);
PagerAdapter realViewPagerAdapter = new MyPagerAdapter(super.getSupportFragmentManager(), fragments);
mViewPager.setAdapter(realViewPagerAdapter);
indicator.setViewPager(mViewPager);
}
}
public void changeScene(View v) {
switch (mViewPager.getCurrentItem()) {
case 0:
mFrag1.changeScene(v);
break;
case 1:
mFrag2.changeScene(v);
break;
case 2:
mFrag3.changeScene(v);
break;
default:
break;
}
}
}
Lastly, here's a gif showing what happens. As you can see, at the beginning "Item 1" has the parallax effect. After switching scenes back and forth, the PageTransformer won't apply anymore.
Thanks in advance !
I will answer my own question in case anyone would bump into the same issue as I did.
The problem came from the rootLayout I was using in the fragment not being "the right one", therefore the TransitionManager was adding an extra layer when going back to the first scene.
Here's what I changed :
Fragment1.java
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//view_pager_root.xml is a simple empty FrameLayout
View v = inflater.inflate(R.layout.view_pager_root, container, false);
RelativeLayout rootLayout = (RelativeLayout) v.findViewById(R.id.p1);
mTransition = new ChangeBounds();
mTransition.setDuration(400);
mStartScene = Scene.getSceneForLayout(rootLayout, R.layout.view_pager_item_default, getContext());
mInfoScene = Scene.getSceneForLayout(rootLayout, R.layout.view_pager_item_details, getContext());
return (v);
}
Since I added another layer into my hierarchy, I also had to change slightly my PageTransformer :
#Override
public void transformPage(View page, float position) {
float coefficient = page.getWidth() * mParallaxCoeff;
//vG is the FrameLayout
ViewGroup vG = (ViewGroup) page;
if (vG.getChildAt(0) instanceof ViewGroup) {
//vG is now the RelativeLayout from the scene
vG = (ViewGroup) vG.getChildAt(0);
for (int i = vG.getChildCount() - 1; i >= 0; --i) {
View v = vG.getChildAt(i);
if (v != null) {
v.setTranslationX(coefficient * (position * position * position));
}
coefficient *= mDistanceCoeff;
}
}
}
I am new to Android and am trying a sample application for showing ViewPagers in a Master-Detail Flow using custom PagerAdapters and FragmentStatePagerAdapters. My application has a list of dummy items managed by a SQLiteDatabase which contain a title String, a description String, a Boolean like status, and a list of images (I plan to implement them as downloading from String urls but presently I'm just trying with a single image resource). I am having two problems in the Detail View.
My intention is to use a ViewPager with a FragmentStatePagerAdapter to show the detail view, which consists of a ViewPager with a custom PagerAdapter for showing the list of images, TextView for title and description, a ToggleButton for the like status and a delete button for deleting items from the list.
Issues:
The ViewPager with the custom PagerAdapter does not display the image. It occupies the expected space and swipes performed on it also behave as expected. Only the image is not visible.
[RESOLVED] On using the delete button, I am able to delete the item from the database, and also update the Master View accordingly, but I am not able to update the Detail View, and the app crashes.
Here is my code:
Code that calls ItemDetailActivity.java
#Override
public void onClick(View v) {
Intent detailIntent = new Intent(getContext(), ItemDetailActivity.class);
detailIntent.putExtra(ItemDetailFragment.ARG_LIST_POSITION, holder.position);
getContext().startActivity(detailIntent);
}
ItemDetailActivity.java
public class ItemDetailActivity extends FragmentActivity {
static ItemDetailPagerAdapter idpa;
static ViewPager detailPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_detail);
idpa = new ItemDetailPagerAdapter(getSupportFragmentManager());
// Show the Up button in the action bar.
getActionBar().setDisplayHomeAsUpEnabled(true);
detailPager = (ViewPager) findViewById(R.id.item_detail_container);
detailPager.setAdapter(idpa);
detailPager.setCurrentItem(getIntent().getIntExtra(ItemDetailFragment.ARG_LIST_POSITION, 0));
}
}
activity_item_detail.xml
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/item_detail_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.trial.piclist.ItemDetailActivity"
tools:ignore="MergeRootFrame" />
ItemDetailFragment.java
public class ItemDetailFragment extends Fragment {
public static final String ARG_ITEM_ID = "item_id";
public static final String ARG_LIST_POSITION = "list_index";
public static final String ARG_TWO_PANE = "is_two_pane";
int position = -1;
long id = -1;
boolean twoPane = false;
ViewPager pager;
private PicItem mItem;
public ItemDetailFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
twoPane = getArguments().getBoolean(ARG_TWO_PANE, false);
position = getArguments().getInt(ARG_LIST_POSITION, -1);
id = getArguments().getLong(ARG_ITEM_ID, -1);
if (id == -1)
id = ItemListFragment.getIdByPosition(position);
setmItem(id);
}
public void setmItem(long id) {
if (id >= 0) {
try {
ItemListActivity.lds.open();
mItem = ItemListActivity.lds.getById(id);
ItemListActivity.lds.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
if (mItem != null) {
List<String> pics = new ArrayList<String>();
pics.add("1");
pics.add("2");
pics.add("3");
pics.add("4");
pics.add("5");
mItem.setPics(pics);
}
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_item_detail,
container, false);
DetailViewHolder holder = new DetailViewHolder();
pager = (ViewPager) rootView.findViewById(R.id.pager);
ImagePagerAdapter adapter = new ImagePagerAdapter(mItem, getActivity(),
inflater, position);
pager.setAdapter(adapter);
holder.position = getArguments().getInt(ARG_LIST_POSITION);
holder.ttv = (TextView) rootView.findViewById(R.id.item_title);
holder.dtv = (TextView) rootView.findViewById(R.id.item_detail);
holder.likeButton = (ToggleButton) rootView
.findViewById(R.id.item_like);
holder.deleteButton = (Button) rootView.findViewById(R.id.item_delete);
rootView.setTag(holder);
if (mItem != null) {
holder.ttv.setText(mItem.getTitle());
holder.dtv.setText(mItem.getDescription());
holder.likeButton.setChecked(mItem.getIsLiked());
holder.likeButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ItemListActivity.lds.open();
ItemListActivity.lds.toggleLike(mItem.getId());
mItem.toggleIsLiked();
ItemListActivity.lds.close();
ItemListFragment.listDisplayHelper.toggleLiked(position);
}
});
holder.deleteButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ItemListActivity.lds.open();
ItemListActivity.lds.removeItem(mItem.getId());
ItemListActivity.lds.close();
ItemListFragment.listDisplayHelper.remove(position);
ItemListActivity.idpa.notifyDataSetChanged();
// What do I do so that the FragmentStatePagerAdapter is
// updated and the viewpager shows the next item.
}
});
}
return rootView;
}
static private class DetailViewHolder {
TextView ttv;
TextView dtv;
ToggleButton likeButton;
Button deleteButton;
int position;
}
}
fragment_item_detail.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context="com.trial.piclist.ItemDetailFragment" >
<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="200dip">
</android.support.v4.view.ViewPager>
<TableRow
android:id="#+id/tableRow1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/item_title"
style="?android:attr/textAppearanceLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello"
android:textIsSelectable="true" />
<Space
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1" />
<include
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="#layout/controls_layout" />
</TableRow>
<ScrollView
android:id="#+id/descScrollView"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/item_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello" />
</LinearLayout>
</ScrollView>
</LinearLayout>
controls_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<ToggleButton
android:id="#+id/item_like"
android:layout_width="30dip"
android:layout_height="30dip"
android:layout_gravity="right"
android:background="#android:drawable/btn_star"
android:gravity="center"
android:text="#string/like_list_item"
android:textOff="#string/empty_text"
android:textOn="#string/empty_text" />
<Button
android:id="#+id/item_delete"
style="?android:attr/buttonStyleSmall"
android:layout_width="30dip"
android:layout_height="30dip"
android:background="#android:drawable/ic_menu_delete"
android:text="#string/empty_text" />
</LinearLayout>
Custom PagerAdapter
ImagePagerAdapter.java
public class ImagePagerAdapter extends PagerAdapter {
LayoutInflater inflater;
List<View> layouts = new ArrayList<>(5);
// Constructors.
#Override
public Object instantiateItem(ViewGroup container, int position) {
if (layouts.get(position) != null) {
return layouts.get(position);
}
View layout = inflater.inflate(R.layout.detail_image,
((ViewPager) container), true);
try {
ImageView loadSpace = (ImageView) layout
.findViewById(R.id.detail_image_view);
loadSpace.setBackgroundColor(0x000000);
loadSpace.setImageResource(R.drawable.light_grey_background);
loadSpace.setAdjustViewBounds(true);
} catch (Exception e) {
System.out.println(e.getMessage());
}
layout.setTag(images.get(position));
layouts.set(position, layout);
return layout;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
}
#Override
public int getCount() {
return 5;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return (((View) object).findViewById((view.getId())) != null);
}
}
FragmentPagerAdapter
ItemDetailPagerAdapter.java
public class ItemDetailPagerAdapter extends FragmentStatePagerAdapter {
public ItemDetailPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment fragment = new ItemDetailFragment();
Bundle args = new Bundle();
args.putLong(ItemDetailFragment.ARG_ITEM_ID, ItemListFragment.getIdByPosition(position));
args.putInt(ItemDetailFragment.ARG_LIST_POSITION, position);
args.putBoolean(ItemDetailFragment.ARG_TWO_PANE, ItemListActivity.mTwoPane);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
openDatabase();
int c = database.getCount();
closeDatabase();
return c;
}
#Override
public int getItemPosition(Object object) {
long mId = ((ItemDetailFragment) object).getmId();
int pos = POSITION_NONE;
openDatabase();
if (database.contains(mId)) {
pos = database.getPositionById(mId);
}
closeDatabase();
return pos;
}
}
Any help is much appreciated. Thanks :)
In your ItemDetailFragment, remove the viewpager from the holder, it should be directly into the returned view, something like this:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_item_detail,
container, false);
pager = (ViewPager) rootView.findViewById(R.id.pager);
ImagePagerAdapter adapter = new ImagePagerAdapter(mItem, getActivity(),inflater, position);
pager.setAdapter(adapter);
return rootView;
}
and the ViewHolder pattern should be applied inside your PagerAdapter.
In ImagePagerAdapter.java, correct the isViewFromObject method -
#Override
public boolean isViewFromObject(View view, Object object) {
return (view == (View) object);
}
This will correct the issue of the ImageView.
In ItemDetailPagerAdapter.java, override the getItemPosition method -
#Override
public int getItemPosition(Object object) {
int ret = POSITION_NONE;
long id = ((ItemDetailFragment) object).getId();
openDatabase();
if (databaseContains(id)) {
ret = positionInDatabase(id);
}
closeDatabase();
return ret;
}
On deleting call the FragmentStatePagerAdapter.NotifyDataSetChanged() method. This will make the Adapter update itself on deleting.
Although, the FragmentStatePagerAdapter uses a list of Fragments and of stored states to implement the adapter. That is also causing trouble. To remove that, implement your own list of Fragments.