I'm currently making a playlist of videos. The flow of this is that from a ListView, it shows the list of the videos in the playlist. Upon clicking on the video, it will open the PlaylistActivity with this layout:
Playlist layout:
Problem:
The videos are working fine because I can hear them being played. However, probably because I used fragments, every time I click the prev or next button the video is being played on the last opened page from the ViewPager.
On the custom PagerAdapter, I inflated the layout with a custom player and an empty LinearLayout container where I will add the fragment.
PlaylistPagerAdapter.java
public class PlaylistPagerAdapter extends PagerAdapter {
List<Playlist> videos;
#Override
public int getCount() {
return videos != null ? videos.size() : 0;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = LayoutInflater.from(container.getContext());
View pagerView = inflater.inflate(R.layout.view_video_player, container, false);
pagerView.setTag(videos.get(position).getId());
container.addView(pagerView);
return pagerView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view.equals(object);
}
public void setVideos(List<Playlist> videos) {
this.videos = videos;
notifyDataSetChanged();
}
public Playlist getItemAt(int position) {
if (position > -1 && position < getCount()) {
return videos.get(position);
} else {
return null;
}
}
public void cleanup() {
if (videos != null && !videos.isEmpty()) {
videos.clear();
videos = null;
}
}
}
view_video_player.xml
<com.example.abd.ui.playlist.PlaylistVideoPlayerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#color/white">
<com.example.abd.ui.misc.CustomVideoView
android:id="#+id/video_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_gravity="top"
android:background="#color/gray_holo_light" />
<ProgressBar
android:id="#+id/progress_bar"
style="#android:style/Widget.ProgressBar.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<LinearLayout
android:id="#+id/video_exit_btn_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|right"
android:background="#drawable/semi_transparent_button_bg"
android:visibility="gone">
<com.gc.materialdesign.views.ButtonFlat
android:id="#+id/btn_video_exit"
android:layout_width="wrap_content"
android:layout_height="38dp"
android:background="#color/white"
android:text="#string/action_done" />
</LinearLayout>
<LinearLayout
android:id="#+id/yt_video_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_gravity="top"
android:background="#color/gray_holo_light"
android:orientation="vertical" />
</com.example.abd.ui.playlist.PlaylistVideoPlayerView>
If the url of the video is from YouTube, then I will set the visibility of the CustomVideoView into GONE and set the LinearLayout ytVideoContainer into VISIBLE so it can show the fragment.
PlaylistVideoPlayerView.java
public void bindYouTubeVideo(FragmentTransaction fragmentTransaction, YouTubeVideo youTubeVideo) {
if (videoView != null && ytVideoContainer != null) {
ytVideoContainer.setVisibility(VISIBLE);
videoView.setVisibility(GONE);
progressBar.setVisibility(GONE);
}
Bundle bundle = new Bundle();
bundle.putSerializable(YOUTUBE_VIDEO_OBJ, youTubeVideo);
YouTubePlayerFragment yt_fragment = new YouTubePlayerFragment();
yt_fragment.setArguments(bundle);
fragmentTransaction
.replace(ytVideoContainer.getId(), yt_fragment)
.commit();
}
A snippet of onPageChanged() listener of the ViewPager:
PlaylistActivity.java
if (url.contains("youtube.com") || url.contains("youtu.be")) {
GetVideosDetailsByIDs getVideosDetailsByIDs = new GetVideosDetailsByIDs();
final String youtubeId = extractYTId(url);
try {
getVideosDetailsByIDs.init(youtubeId);
GetYouTubeVideosTask task = new GetYouTubeVideosTask(getVideosDetailsByIDs,
new GetYouTubeVideosTask.VideoResultListener() {
#Override
public void onResults(List<YouTubeVideo> videosList) {
if (videosList != null && !videosList.isEmpty()) {
YouTubeVideo youTubeVideo = videosList.get(0);
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
if (!isFinishing()) {
videoView.bindYouTubeVideo(fragmentTransaction,
youTubeVideo);
}
} else {
handleGetVideoStreamFailure();
}
}
});
task.execute();
} catch (IOException e) {
Timber.e(e, "Failed to play the youtube video.");
handleGetVideoStreamFailure();
}
}
It seems like the fragment was not added to the current page, does this have something to do with the AsyncTask? or with the way I added the fragment?
If you want to replace a fragment in your viewpager, you have to notify your adapter of the change. Your list of fragments needs to be updated to remove the 3rd fragment and add a new one in its place. After you've done that, you call notifyDataSetChanged in your adapter.
You could have an method like this in your adapter:
public void replaceFragment(Fragment fragment, String title, int index) {
mFragmentList.remove(index);
mFragmentList.add(index, fragment);
// do the same for the title
notifyDataSetChanged();
}
Related
I have a ListView that uses a CardView to inflate it's layout. When the user clicks on the the first item in the ListView, this should change the Fragment. However, I am unsure of how to do this. I attempted to change the Fragment in the adapter class (CustomAdapter.java) and it didn't work. I also have tried doing this in the Fragment the ListView is in but it didn't work either (the app didn't crash when I clicked one of the items - nothing happened):
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new DesignsWorkshopFragment();
break;
}
if (fragment != null) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(null);
ft.commit();
}
}
});
SuppliersFragment.java:
public class SuppliersFragment extends Fragment {
CustomAdapter adapter;
ListView lv;
public SuppliersFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_suppliers, container, false);
lv = view.findViewById(R.id.lvFragmentSuppliers);
adapter = new CustomAdapter(getContext(), getData());
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new DesignsWorkshopFragment();
break;
}
if (fragment != null) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(null);
ft.commit();
}
}
});
return view;
}
private ArrayList getData() {
ArrayList<SuppliersCardview> suppliersCardview = new ArrayList<>();
SuppliersCardview s = new SuppliersCardview();
s.setThumbnail(R.drawable.designs_workshop_logo);
s.setName("Designs Workshop");
suppliersCardview.add(s);
s = new SuppliersCardview();
s.setThumbnail(R.drawable.organic_clothing_logo);
s.setName("Organic Clothing Industries");
suppliersCardview.add(s);
s = new SuppliersCardview();
s.setThumbnail(R.drawable.suns_sewing_ltd);
s.setName("Sun's Sewing Ltd");
suppliersCardview.add(s);
return suppliersCardview;
}}
CustomAdapter.java:
public class CustomAdapter extends BaseAdapter {
Context c;
ArrayList<SuppliersCardview> suppliersCardview;
public CustomAdapter(Context c, ArrayList<SuppliersCardview> suppliersCardview) {
this.c = c;
this.suppliersCardview = suppliersCardview;
}
#Override
public int getCount() {
return suppliersCardview.size();
}
#Override
public Object getItem(int position) {
return suppliersCardview.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(c).inflate(R.layout.cardview_layout, parent, false);
}
final SuppliersCardview s = (SuppliersCardview) this.getItem(position);
ImageView imageView = convertView.findViewById(R.id.ivSupplierLogo);
TextView textView = convertView.findViewById(R.id.tvSupplierName);
imageView.setImageResource(s.getThumbnail());
textView.setText(s.getName());
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Attempted to change fragment here in a switch statement
}
});
return convertView;
}
SuppliersCardview.java:
public class SuppliersCardview {
private String name;
private int thumbnail;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getThumbnail() {
return thumbnail;
}
public void setThumbnail(int thumbnail) {
this.thumbnail = thumbnail;
}}
SuppliersFragment XML:
<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="com.miguelpeachey.marketplacesimulator.Fragments.SuppliersFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/tvBrowseSuppliersHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#bfbdbd"
android:fontFamily="#font/nunito_sans"
android:paddingBottom="5dp"
android:paddingStart="10dp"
android:paddingTop="10dp"
android:text="Browse Suppliers"
android:textSize="25sp" />
<ListView
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"
android:id="#+id/lvFragmentSuppliers"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#color/colorTransparent"
android:dividerHeight="20dip"/>
</LinearLayout>
CardView XML:
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/tools"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/cardView"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_margin="40dp"
android:orientation="vertical"
app:cardPreventCornerOverlap="false"
app:ignore="NamespaceTypo"
card_view:cardBackgroundColor="#cccbcb"
card_view:cardCornerRadius="15dp"
card_view:cardElevation="5dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:orientation="vertical">
<ImageView
android:id="#+id/ivSupplierLogo"
android:layout_width="150dp"
android:layout_height="120dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:src="#drawable/ic_launcher_background" />
<TextView
android:id="#+id/tvSupplierName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/ivSupplierLogo"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:fontFamily="#font/brawler"
android:text="Supplier"
android:textColor="#232323"
android:textSize="22sp" />
</RelativeLayout>
So how can I replace/change fragments on the ListView's item click that uses a CardView as its layout? Other people's solutions did not help me.
I have used this website as a tutorial to create the CardView and inflate the ListView's layout (some code here is from the website).
You have your object of fragment now you need to use fragment manager and replace existing fragment with fragment you want to show.
DesignsWorkshopFragment fragment2=new DesignsWorkshopFragment();
FragmentManager fragmentManager=getActivity().getFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_main,fragment2,"tag");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Only creating your fragment's instance will not show it in activity.
Adding and replacing of fragment is done inside activity.You need to notify your activity on the click of item view in your ListView.This can be done using interfaces.
create one interface:
public interface ClickListener{
public void onClick();
}
Implement this interface in your activity.And when you are creating the Fragment pass "this" as reference inside fragment's constructor.Like this :
fragment = new DesignsWorkshopFragment(this);
Inside fragment, you need to create the interface reference.
private ClickListener clickListener ;
Inside fragment initialize this interface reference
DesignsWorkshopFragment(ClickListener clickListener){
this.clickListener = clickListener;
}
Now do the same thing when you are creating adapter.
adapter = new CustomAdapter(getContext(), getData(),clickListener);
Inside adapter create and intialize interface reference.
private ClickListener clickListener ;
public CustomAdapter(Context c, ArrayList<SuppliersCardview> suppliersCardview,
ClickListener clickListener ) {
this.c = c;
this.suppliersCardview = suppliersCardview;
this.clickListener = clickListener;
}
and whenever a click is happening. just call the interface method.
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
clickListener.onClick();
}
});
this will give a callback inside your activity's interfcae implementation. In here
public void onClick(){
//write your code for adding or replacing fragment.
}
I managed to get this working by just removing
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
in my CustomAdapter.java class.
Asking this question because I did not find solution/suggestions after searching for hours. All answered solutions are with Fragment. What I am looking for ViewPagerAdapter and FrameLayout.
My ViewPagerAdapter xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/promotion_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="#+id/some_image"
android:layout_width="match_parent"
android:layout_height="#dimen/view_pager_height"
android:scaleType="fitXY" />
<FrameLayout
android:id="#+id/youtube_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
//Some other view items
</RelativeLayout>
My ViewPagerAdapter Java code:
public class ArticleViewPagerAdapter extends PagerAdapter {
public String TAG = ArticleViewPagerAdapter.class.getSimpleName();
private ArrayList<Article> mArticleList = new ArrayList<>();
private Activity mContext;
private LayoutInflater mLayoutInflater;
private FragmentManager mFragmentManger;
private YouTubePlayerListener mYouTubePlayerListener;
public ArticleViewPagerAdapter(Activity context, ArrayList<Article> articleList, FragmentManager fragmentManager, YouTubePlayerListener youTubePlayerListener) {
this.mContext = context;
this.mArticleList = articleList;
this.mFragmentManger = fragmentManager;
this.mYouTubePlayerListener = youTubePlayerListener;
mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return mArticleList.size();
}
#Override
public boolean isViewFromObject(#NonNull View view, #NonNull Object object) {
return view == (object);
}
#NonNull
#Override
public Object instantiateItem(#NonNull ViewGroup container, int position) {
View itemView = mLayoutInflater.inflate(R.layout.activity_news, container,
false);
itemView.setTag(position);
updateView(itemView, position);
((ViewPager) container).addView(itemView);
return itemView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
private void updateView(View itemView, int position) {
final int index = position;
final View finalView = itemView;
//Initializing the view items
final ImageView mNewsImage = itemView.findViewById(R.id.some_image);
final FrameLayout mYoutubeFragment = itemView.findViewById(R.id.youtube_fragment);
//Let's Test using this
final YouTubePlayerSupportFragment youTubePlayerFragment = YouTubePlayerSupportFragment.newInstance();
ResArticle articleResponse = response.body(); //Got response from API
if (articleResponse != null && articleResponse.getData() != null) {
final Article article = articleResponse.getData();
final String pageUrl = SHARE_BASE_URL + article.getArticleId();
if (article != null) {
if (article.getArticleType()==Constants.ARTICLE_TYPE_NEWS) {
//Basically setting visibility But you can ignore this part
mNewsImage.setVisibility(View.VISIBLE);
mYoutubeFragment.setVisibility(View.GONE);
}
if(article.getArticleType()==Constants.ARTICLE_TYPE_VIDEO) {
Log.d(TAG,"Article Type is Video");
mYoutubeFragment.setVisibility(View.VISIBLE);
mNewsImage.setVisibility(View.GONE);
youTubePlayerFragment.initialize(mContext.getString(R.string.web_client_id), new YouTubePlayer.OnInitializedListener() {
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean wasRestored) {
youTubePlayer.setShowFullscreenButton(false);
youTubePlayer.cueVideo("video_id");
if (mYouTubePlayerListener!=null)
mYouTubePlayerListener.setYouTubePlayer(youTubePlayer);
}
#Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
Log.e(TAG, "Youtube Video initialization failed");
}
});
FragmentTransaction transaction = mFragmentManger.beginTransaction();
transaction.replace(R.id.youtube_fragment, youTubePlayerFragment).commit();
}
}
} else {
Toast.makeText(mContext, mContext.getString(R.string.article_info_not_found), Toast.LENGTH_SHORT).show();
Log.e(TAG, "Article info not found");
}
}
}
}
And I am calling the adapter from the Activity NOT the YouTubeBaseActivity.
Problem:
YouTube video playback stopped due to unauthorized overlay on top of player. The YouTubePlayerView is not contained inside its ancestor android.widget.FrameLayout The distances between the ancestor's edges and that of the YouTubePlayerView is: left: 0, top: 0, right: 0, bottom: 0 (these should all be positive).
Why I am getting the error?
As I am loading Multiple YouTube Player using the ViewPager. As we know the viewpager loads next, previous and current item. So current YouTube video gets initialized and so does the next one. But As current YouTubePlayer overlays the next one(which is pre-loaded).
Please help. Or should I use any library to load YouTube videos.
fix this by removing the padding in the YouTubePlayerView in the layout. So your layout looks like this:
<com.google.android.youtube.player.YouTubePlayerView
android:id="#+id/video_player"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#000" />
why you are using instantiateItem instead of getItem in adapter?
maybe I'm tired but I miss something in what's happening in my code. I have an activity with fragments.
My activity HomeActivity calls a webservice to fill a List (my business object), it does this onResume().
My fragment WalletFragment has a mehtod refreshCardListView() that uses an adapter to display the list. It does this onResume().
What I was doing and that was working until now was:
HomeActivity.onCreate() displays WalletFragment,
WalletFragment.onResume() calls this.refreshCardList() but at this
instant cardList is null so the adapter displays nothing
HomeActivity.onResume() calls webservice, which on success calls
walletFragment.refreshCardList(), this time cardList has been filled
by the webservice so tid displays the list correctly.
Now I thout it was stupid to call refreshList twice so I tried to move the displayWalletFragment from HomeActivity.onCreate() to the success callback of the webservice and remove the call to refreshCardList from HomeActivity and leaving it only in WalletFragment.onResume(), so it'd go like this:
HomeActivity.onResume() calls webservice, which on success displays WalletFragment, WalletFragment.onResume() calls this.refreshCardList(), cardList having been filled by the webservice.
However at this point my adapter crashes, because parent.getWidth() == 0 (and I needed parent width to display card images).
I don't understad why, by moving this bit of code, the parent view would now not be initialized at this point, do you have an idea?
So this is the original code I used that is working, the only things I changed are removing displayWalletFragment(false) from onCreate and moving it in the success return of refreshCardList and removing walletFragment.refreshCardListView() from there.
HomeActivity.java
public class HomeActivity extends Activity {
CardService cardService = new CardService(this);
UserService userService = new UserService(this);
User user = null;
Set<WegaCard> userCards = null;
ProfileFragment profileFragment;
WalletFragment walletFragment;
/*
* Saving card images for performance concerns.
*/
Map<String, Bitmap> cardsImageBitmaps = new HashMap<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
initializeComponents();
styleCompnents();
displayWalletFragment(false);
}
#Override
protected void onResume() {
Log.d(this, "fired HomeActivity.onResume()");
super.onResume();
user = null;
userCards = null;
refreshUser(
new SingleResultCallback<User>() {
#Override
public void onResponse(User cards) {
Log.d(this, "user: " + user.toString());
HomeActivity.this.user = user;
profileFragment.refreshUser();
}
},
new ErrorCallback() {
#Override
public void onResponse(Throwable error) {
Log.e(this, "error: " + error.toString());
}
});
refreshCardList(
new SingleResultCallback<Set<WegaCard>>() {
#Override
public void onResponse(Set<WegaCard> cards) {
Log.d(this, "cards: " + cards.toString());
userCards = cards;
walletFragment.refreshCardListView();
}
},
new ErrorCallback() {
#Override
public void onResponse(Throwable error) {
Log.e(this, "error: " + error.toString());
}
});
}
private void refreshCardList(SingleResultCallback<Set<WegaCard>> successCallback, ErrorCallback errorCallback) {
Log.d(this, "fired HomeActivity.refreshCardList()");
// First empty list...
userCards = new LinkedHashSet<>();
// ...then fill it back
cardService.getCards(false, true, successCallback, errorCallback);
}
private void refreshUser(SingleResultCallback<User> successCallback, ErrorCallback errorCallback) {
Log.d(this, "fired HomeActivity.refreshUser()");
// First empty user...
userCards = new LinkedHashSet<>();
// ...then recreate it
userService.getUser(successCallback, errorCallback);
}
public void displayWalletFragment(boolean addToBackStack) {
displayFragment(WalletFragment.newInstance(), addToBackStack);
}
public void displayCardFragment(String cardNumber, boolean addToBackStack) {
displayFragment(CardFragment.newInstance(cardNumber), addToBackStack);
}
public void displayProfileFragment(boolean addToBackStack) {
displayFragment(ProfileFragment.newInstance(), addToBackStack);
}
private void displayFragment(HomeFragment fragment, boolean addToBackStack) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.home_fragment, fragment);
if (addToBackStack) {
fragmentTransaction.addToBackStack(null);
}
fragmentTransaction.commit();
}
public void profileEdit(View view) {
ActivityLauncher.getInstance().startProfileActivityForResult(this, ProfileActivity.ProfileEditMode.EDIT_PROFILE, user);
}
public Map<String, Bitmap> getCardsImageBitmaps() {
return cardsImageBitmaps;
}
}
WalletFragment.java
public class WalletFragment extends HomeFragment {
List<WegaCard> cardList;
ListView cardListView;
WegaCardAdapter adapter;
public static WalletFragment newInstance() {
WalletFragment fragment = new WalletFragment();
// Bundle args = new Bundle();
// fragment.setArguments(args);
return fragment;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
activity.walletFragment = this;
cardListView = (ListView) getView().findViewById(R.id.fragment_home_wallet_list);
cardListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
activity.displayCardFragment(cardList.get(position).getCardNumber(), true);
}
});
}
#Override
public void onResume() {
Log.d(this, "fired WalletFragment.onResume()");
super.onResume();
refreshCardListView();
}
void refreshCardListView() {
Log.d(this, "fired WalletFragment.refreshCardListView()");
// First empty list...
cardList = new ArrayList<>();
cardList.addAll(activity.userCards);
adapter = new WegaCardAdapter(activity, R.layout.adapter_card_item, cardList);
cardListView.setAdapter(adapter);
getView().findViewById(R.id.fragment_home_wallet_empty).setVisibility(cardList.isEmpty() ? View.VISIBLE : View.GONE);
}
}
WegaCardAdapter.java
public class WegaCardAdapter extends ArrayAdapter<WegaCard> {
public WegaCardAdapter(#NonNull Context context, #LayoutRes int resource, #NonNull List<WegaCard> objects) {
super(context, resource, objects);
}
/**
* Data that should appear in the view should be added here
*/
private class ViewHolder {
ImageView imageView;
}
/*
* Note: using layout_height="match_parent" on the ListView helps Android calculate faster
* the elements that are displayed on screen, and prevent the array adapter for calling
* getView() too many times, thus improving the display speed
*/
public View getView(int position, View convertView, ViewGroup parent) {
Log.d(this, "fired WegaCardAdapter.getView(" + position + ")");
ViewHolder holder = null;
WegaCard card = getItem(position);
LayoutInflater mInflater = (LayoutInflater) getContext().getSystemService(android.app.Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.adapter_card_item, null);
holder = new ViewHolder();
holder.imageView = (ImageView) convertView.findViewById(R.id.adapter_card_image);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
Bitmap cardImage = null;
if (getContext() instanceof HomeActivity) {
Log.d(this, "In home activity \\o/");
Map<String, Bitmap> savedBitmaps = ((HomeActivity) getContext()).getCardsImageBitmaps();
if (savedBitmaps.containsKey(card.getCardNumber())) {
Log.d(this, "Found saved image, using it ^^");
cardImage = savedBitmaps.get(card.getCardNumber());
}
else {
Log.d(this, "Didn't found saved image éè building and saving it for later!");
cardImage = card.getRoundedScaledBitmap(getContext(), parent.getWidth());
savedBitmaps.put(card.getCardNumber(), cardImage);
}
}
else {
Log.d(this, "Not in home activity?");
cardImage = card.getRoundedScaledBitmap(getContext(), parent.getWidth());
}
holder.imageView.setImageBitmap(cardImage);
return convertView;
}
}
activity_home.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:auto="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<!-- Fragment will be displayed here -->
<LinearLayout
android:id="#+id/home_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</LinearLayout>
</ScrollView>
</RelativeLayout>
fragment_home_wallet.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">
<LinearLayout
android:id="#+id/fragment_home_wallet_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<LinearLayout
android:id="#+id/fragment_home_wallet_empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:visibility="gone">
<ImageView
android:src="#drawable/icon_card_white"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.gaetanl.aspa.ui.component.StaticTextView
android:id="#+id/fragment_home_wallet_empty_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/defaultSpacing"
android:text="#string/dashboard_text_nocard" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/defaultSpacing"
android:gravity="center_vertical"
android:orientation="horizontal">
<com.gaetanl.aspa.ui.component.StaticTextView
android:id="#+id/fragment_home_wallet_empty_text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/dashboard_text_tap1" />
<ImageView
android:src="#drawable/icon_plus_white"
android:layout_width="#dimen/inlineIcon"
android:layout_height="#dimen/inlineIcon"
android:layout_marginLeft="#dimen/wordSpacing"
android:layout_marginRight="#dimen/wordSpacing" />
<com.gaetanl.aspa.ui.component.StaticTextView
android:id="#+id/fragment_home_wallet_empty_text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/dashboard_text_tap2" />
</LinearLayout>
</LinearLayout>
<!-- Note: using layout_height="match_parent" on the ListView helps Android calculate faster
the elements that are displayed on screen, and prevent the array adapter for calling
getView() too many times, thus improving the display speed -->
<ListView
android:id="#+id/fragment_home_wallet_list"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
</LinearLayout>
I found the solution here: When should I get Width View in Fragment.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.post(new Runnable() {
#Override
public void run() {
// do operations or methods involved
// View.getWidth(); or View.getHeight();
// here
}
});
}
You can try calling just displayWalletFragment(false); on your success callback and move walletFragment.refreshCardListView(); to the onViewCreated() of your WallentFragment.
This will ensure the right sequence of your Fragment being created and the list being populated.
I'm trying to show images from Drawable in view pager using PagerAdapter for that, I have written below code--
// Call to the PagerAdapter
public void showAwardsBadgesAlert()
{
// custom dialog
final Dialog dialog = new Dialog(context, R.style.MyAlertDlgTheme);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.awards_badges_dlg_layout);
dialog.setCanceledOnTouchOutside(false);
dialog.setCanceledOnTouchOutside(true);
ViewPager awardsBadgesPager = (ViewPager) dialog.findViewById(R.id.awardsBadgesPager);
AwardsBadgesAdapter awardsBadgesAdapter = new AwardsBadgesAdapter(context, feedObject.getAwardStatistics().getAwardsBdgesList());
awardsBadgesPager.setAdapter(awardsBadgesAdapter);
dialog.show();
}
// Below is my Adapter Class--
public class AwardsBadgesAdapter extends PagerAdapter
{
private Context context;
private ArrayList<AwardsBadges> awardsList;
public AwardsBadgesAdapter(Context context, ArrayList<AwardsBadges> awardsList)
{
this.context = context;
this.awardsList = awardsList;
}
#Override
public int getCount()
{
if(awardsList != null)
{
return awardsList.size();
}
return 0;
}
#Override
public boolean isViewFromObject(View view, Object object)
{
return view == object;
}
#Override
public Object instantiateItem(final View container, final int position)
{
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.awards_badges_dlg_item, null);
ImageView ivAwards = (ImageView) layout.findViewById(R.id.ivAwardsBadges);
AwardsBadges currBadge = awardsList.get(position);
if(currBadge.getImageName()!=null && currBadge.getImageName().equalsIgnoreCase("pink star diamond"))
{
Picasso.with(context).load(R.drawable.pinkstar).into(ivAwards);
}
else if(currBadge.getImageName()!=null && currBadge.getImageName().equalsIgnoreCase("tanzanite"))
{
Picasso.with(context).load(R.drawable.tanzanite).into(ivAwards);
}
else if(currBadge.getImageName()!=null && currBadge.getImageName().equalsIgnoreCase("painite"))
{
Picasso.with(context).load(R.drawable.painite).into(ivAwards);
}
else if(currBadge.getImageName()!=null && currBadge.getImageName().equalsIgnoreCase("taaffeite"))
{
Picasso.with(context).load(R.drawable.taaffeite).into(ivAwards);
}
return layout;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object)
{
((ViewPager) container).removeView((View) object);
}
#Override
public float getPageWidth(int position)
{
return (0.33f);
}
}
// Below is my dialog xml--
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v4.view.ViewPager
android:id="#+id/awardsBadgesPager"
android:layout_width="match_parent"
android:layout_height="#dimen/sz_seventy"
android:layout_below="#+id/txtPlace"
android:layout_margin="10dp"
android:background="#color/tipstransperent"
android:padding="10dp"
android:visibility="visible" >
</android.support.v4.view.ViewPager>
</RelativeLayout>
// Below is ViewPager Item xml--
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp" >
<ImageView
android:id="#+id/ivAwardsBadges"
android:layout_width="#dimen/sz_fifty"
android:layout_height="#dimen/sz_fifty"
android:layout_centerInParent="true" />
</RelativeLayout>
// Below is the screen shot explaining currently how it is showing empty ViewPager--
When I debug the app everything seems fine but don't know why Images are not getting displayed in ViewPager. Please Help..
First, you should be overriding the instantiateItem() method with ViewGroup as the first parameter, not the one with View as the first parameter. The latter is deprecated.
Then, you need to add your inflated View to the container in the PagerAdapter's instantiateItem() method. Quoting the docs for the instantiateItem() method:
The adapter is responsible for adding the view to the container given here
Simply add container.addView(layout); to the instantiateItem() method, before the return statement.
((ViewPager) container).addView(layout);
Add above statement in your instantiateItem() method, before the return statement. This will surely help you.
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.