How to update Fragment when scrolled in [Scrollable Tabs + Swipe] Navigation-Android? - android

So I'm using the Scrollable tabs + swipe navigations to play different music files on different tabs screens.
Here's my modified OnCreateView for the default fragment that's auto-generated
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_dummy,
container, false);
TextView dummyTextView = (TextView) rootView
.findViewById(R.id.sT);
dummyTextView.setText(Integer.toString(getArguments().getInt(
ARG_SECTION_NUMBER)));
AssetFileDescriptor fda;
MediaPlayer amp = new MediaPlayer();
try {
fda = rootView.getContext().getAssets().openFd("songname.mp3");
amp.reset();
amp.setDataSource(fda.getFileDescriptor());
amp.prepare();
amp.start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return rootView;
}
Here I just have a textview that shows the index number of screen. Say first screen shows "1", 2nd one shows "2" in a textView ...and so on.
I want an imageView for each screen too, but I can do this.
The trouble is with playing audio.
Right now it just plays a song when the screen starts up. Say the song is playing.
If the user swipes left or right, how to change the song playing ? I need to stop this one, change the "setDataSource" according to the index number (ARG_SECTION_NUMBER)... and play it again .
But how to know if the user swiped and changed the open tab ? (whether by scrollable tab or swipe)
On what User event do I make these changes ? Can I set something that by default stops the playing song and switches over to the next one as the screen changes...?
I intend to add a Play/Pause button eventually. Even with that I would want to change resources with screens..Hence this question
Thnx !

ViewPager has a setOnPageChangeListener() method that will allow you to set an object that gets a callback when a new page becomes the one the user is looking at.
something like this will get you on the right path:
mPageChangeListener = new OnPageChangeListener() {
#Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
}
#Override
public void onPageSelected(int pos) {
playSoundForPage(pos);
}
};
yourViewPager.setOnPageChangeListener(mPageChangeListener);
however you'll have to put this in whatever owns your ViewPager (activity, or fragment) and not your Adapter.
Or you can use this:
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) { }
else { }
}

Related

Video is not getting paused in ViewPager

I m using viewpager and its adapter i m displaying image and video as per condition.
I don't have fragment because i m using PagerAdapter.
Code:
pager.setOnPageChangeListener(pageChangeListener);
pager.post(new Runnable() {
#Override
public void run() {
pageChangeListener.onPageSelected(pager.getCurrentItem());
}
});
}
ViewPager.OnPageChangeListener pageChangeListener = new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrollStateChanged(int arg0) {
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageSelected(int position) {
View view = mediaFullScreenImageAdapter.getActiveView(pager);
if (selectedPhotosByDate.get(position).getMessagetype().equalsIgnoreCase("VIDEO")) {
CustomVideoPlayer video_player = (CustomVideoPlayer) view.findViewById(R.id.video_player);
if (video_player.isPlaying()) {
Log.v("THISCALLEDD", "Y" + " : " + position);
video_player.pause();
}
}
}
};
#Nullable
public View getActiveView(final ViewPager viewPager) {
final PagerAdapter adapter = viewPager.getAdapter();
if (null == adapter || adapter.getCount() == 0 || viewPager.getChildCount() == 0) {
return null;
}
int position;
final int currentPosition = viewPager.getCurrentItem();
for (int i = 0; i < viewPager.getChildCount(); i++) {
final View child = viewPager.getChildAt(i);
final ViewPager.LayoutParams layoutParams = (ViewPager.LayoutParams) child.getLayoutParams();
if (layoutParams.isDecor) {
continue;
}
final Field positionField;
try {
positionField = ViewPager.LayoutParams.class.getDeclaredField("position");
positionField.setAccessible(true);
position = positionField.getInt(layoutParams);
} catch (NoSuchFieldException e) {
break;
} catch (IllegalAccessException e) {
break;
}
if (position == currentPosition) {
return child;
}
}
return null;
}
Update:
selectedPhotosByDate = appDatabase.chatMessagesDao().getMediaByGroupId(topicid, "Y");
if (selectedPhotosByDate.size() > 0 && selectedPhotosByDate != null) {
mediaFullScreenImageAdapter = new MediaFullScreenImageAdapter(MediaFullScreenSlideActivity.this, selectedPhotosByDate);
pager.setAdapter(mediaFullScreenImageAdapter);
for (int i = 0; i < selectedPhotosByDate.size(); i++) {
if (messageid == selectedPhotosByDate.get(i).getMessageId()) {
position = i;
break;
}
}
pager.setCurrentItem(position);
pager.setOffscreenPageLimit(selectedPhotosByDate.size());
}
I am able to get logcat value . But my video doesn't get pause.
If my video is playing and user swipe for other item playing video must be paused.
Advanced help would be appreciated!
Based on the documentation here, onPageSelected is called when a new page is selected. That means, the active view that you are trying to get using the currentItem from the ViewPager will return you the current selected item rather than the previously selected item. So your reference to video_player is also wrong and hence it is not working.
A simple way to do this is to have a variable currentPosition. Update it in onPageSelected but before updating, get its view and pause the video. This way whenever you access it, you will first get the previous index and then you will update it to the current index for the next time.
As per my understanding ,you want to pause previous video when user swipe in viewpager .
#Override
public void onPageSelected(int position) {
View view = mediaFullScreenImageAdapter.getActiveView(pager);
if (selectedPhotosByDate.get(position).getMessagetype().equalsIgnoreCase("VIDEO")) {
CustomVideoPlayer video_player = (CustomVideoPlayer) view.findViewById(R.id.video_player);
if (video_player.isPlaying()) {
Log.v("THISCALLEDD", "Y" + " : " + position);
video_player.pause();
}
}
}
you are getting view object of current active position ,but you want to pause video of (position - 1 ),you need to have view object of previous position .
Finally resolved the issue.
I moved this code
View view = mediaFullScreenImageAdapter.getActiveView(pager);
CustomVideoPlayer video_player = (CustomVideoPlayer) view.findViewById(R.id.video_player);
video_player.pause();
to onPageScrolled() method instead of onPageSelected() method.
This worked for me with a Youtube video playing as an embedded iFrame in a WebView:
viewPager.addOnPageChangeListener(object : SimpleOnPageChangeListener() {
override fun onPageSelected(position: Int) {
// NOTE: this workaround pauses any playing Youtube video in the WebView, if the video screen is being switched out.
// This works by getting the ViewPager#focusedChild, which will be the WebView if that screen is currently in focus,
// before the next selected ViewPager screen gets switched-to/loaded.
viewPager.focusedChild?.findViewById<WebView>(R.id.video_view)?.onPause()
// NOTE: we do a postDelay below, to ensure the WebView gets put back into its resume state, if it being switched to.
// This is delayed, so that this happens after the ViewPager screen with the WebView, has time to load it into place.
postDelayed({ viewPager.focusedChild?.findViewById<WebView>(R.id.video_view)?.onResume() }, 200)
}
})

Is it possible to get the position of views inside ViewHolder for the RecyclerView?

The ViewHolder I have contains views that are needed for each item of my RecycleView, which are two TextViews, PlayPauseView, and AppCompatSeekBar. In the constructor I have initialized them to their ids of my layout, and is ready for my Adapter class to extend it. The problem is I have this PlayPauseView that needs to be toggled at the correct position for it to function right, because if I press the view at another position, the previous position is still toggled. Here's an image for better understanding.
The yellow means that it is currently playing, but two cannot play at the same time so I was hoping to get the position of the view inside the RecyclerView item.
This is from the Holder class
TextView mInstrumentalName, mProducer;
PlayPauseView mPlayButton; // Need to add pause/stop
AppCompatSeekBar mMusicSeekbar;
ItemClickListener itemClickListener;
public TrackHolder(View itemView) {
super(itemView);
mInstrumentalName = (TextView) itemView.findViewById(R.id.instrumental_name);
mProducer = (TextView) itemView.findViewById(R.id.producer);
mPlayButton = (PlayPauseView) itemView.findViewById(R.id.play_pause);
mMusicSeekbar = (AppCompatSeekBar) itemView.findViewById(R.id.music_seekbar);
itemView.setOnClickListener(this);
}
This is from the Adapter class
#Override
public void onBindViewHolder(#NonNull final TrackHolder holder, final int position) {
holder.mInstrumentalName.setText(tracks.get(position).getInstrumentalName());
holder.mProducer.setText(tracks.get(position).getProducer());
holder.mPlayButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.mPlayButton.toggle();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
if (mediaPlayer.isPlaying()) {
mediaPlayer.reset();
try {
mediaPlayer.setDataSource(tracks.get(position).getMusicLink());
} catch (IOException e) {
e.printStackTrace();
}
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
mediaPlayer.prepareAsync();
} else {
try {
mediaPlayer.setDataSource(tracks.get(position).getMusicLink());
previous_link = tracks.get(position).getMusicLink();
} catch (IOException e) {
e.printStackTrace();
}
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
mediaPlayer.prepareAsync();
}
}
});
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.release();
}
});
holder.setItemClickListener(new ItemClickListener() {
#Override
public void onItemClick(View v, int pos) {
Toast.makeText(context, Integer.toString(tracks.size()), Toast.LENGTH_SHORT).show();
}
});
}
If you want to get position in your view holder class then you can call getAdapterPosition() inside your class. this will return you the clicked position in view holder class
I finally found a solution. So what I did instead of focusing on the views inside of the ViewHolder, I refreshed/updated the whole item in the RecyclerView, meaning it will refresh the toggle state of the previous item. Here's a code snipped if anyone in the future has any trouble on the same question.
private int start_notifying = 0;
private int previous_pos = -1;
So start notifying is at 0 because you don't want to refresh the item until you toggled the play button at least once, and set the current position to become the previous position when you want to press a different list item. You then increment so you can start refreshing items on the next item pressed. Using notifyItemChanged(previous_pos) refreshed the item of the previous position that was pressed, making the play button go back to its normal state.
if (start_notifying > 0) {
notifyItemChanged(previous_pos);
previous_pos = position;
} else {
previous_pos = holder.getAdapterPosition();
Log.d("previous_pos", Integer.toString(holder.getAdapterPosition()));
start_notifying++;
}

Issue related to view pager and circle page indicator

I have four pages/screens in my view pager and I am using Circle page indicator for displaying the position of the screen. It works perfectly.
Now I need to add one more indicator circle even though the screen count is 4. Up on crossing the 4 the screen, I want to display another activity.
I have searched and found a solution for moving to another activity before the fake page (5th page is shown). Here is the code:
#Override
public Object instantiateItem(final ViewGroup container, int position) {
// TODO Auto-generated method stub
((ViewPager) container).setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// skip fake page (first), go to last page
if (position == 4) {
//instead of activity call, I am checking whether it's working or not
((ViewPager) container).setCurrentItem(0, false);
}
}
#Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
}
});
return super.instantiateItem(container, position);
}
But the problem is that, When I am doing this, the circle page indicator stops working.
Here is code for setting the adapter to circle page indicator:
mVpAdvertisement.setAdapter(mAdapter);
mCpIndicator.setViewPager(mVpAdvertisement);
mCpIndicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener()
{
#Override
public void onPageSelected(int position)
{
// on changing the pages during swipe
if(position==0)
{
}
}
#Override
public void onPageScrollStateChanged(int arg0)
{
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2)
{
}
});
I want to display 5 circles and upon swiping from 4th screen in view pager, I want application to display another activity, without showing the 5th screen (dummy screen) in view pager.
This is the library I am using: https://github.com/JakeWharton/Android-ViewPagerIndicator
I know this is too late, even the person posted the question got the answer also, but as it may help others to find the quick answer i am posting the answer.
Use two image(circle) for indicator one is for off and another for on. use frame layout to show the indicator. when user slide the viewPager just change the image. You can download the complete solutions which i have developed and working fine for me.
http://javaant.com/viewpager-with-circle-indicator-in-android

ListView play button

This might have been asked plenty of times already but I can't seem to get an actual answer to this. I have an adapter that takes data from an API and converts it into a listview. The row has its own Play button in it. When clicking on the play button, inside the row, it should change the button to a pause button. When I click on a different row's play button, the last button clicked should go back to a play button. I know it's setimageresource on the buttons but I can't seem to track my last button clicked. Here are my codes:
This is part of the adapter and
#Override
public View getView(final int pos, View ConvertView, ViewGroup parent) {
final MyViewHolder holder;
if (ConvertView == null){
ConvertView = layoutinflater.inflate(R.layout.row, parent, false);
holder = new MyViewHolder();
holder.plays = (ImageButton) ConvertView.findViewById(R.id.plays);
holder.plays.setFocusable(false);
play = playdata.get(pos);
holder.posturl= play.getposturl();
mStartPlaying = true;
player = new MediaPlayer();
// player.setOnCompletionListener(onCompletion);
// player.setOnErrorListener(onError);
holder.plays.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
String url = holder.posturl;
if (!mStartPlaying){
holder.plays.setImageResource(R.drawable.ic_action_stop);
startPlaying(url);
mStartPlaying = true;
} else{
holder.plays.setImageResource(R.drawable.ic_action_play);
player.stop();
mStartPlaying = false;
}
}
private void startPlaying(String url) {
// TODO Auto-generated method stub
try {
player.reset();
player.setDataSource(url);
// mPlayer.setDataSource(mFileName);
player.prepareAsync();
player.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
player.start();
}
});
} catch (IOException e) {
Log.e("preparefailed", "prepare() failed");
}
}
});
if (!player.isPlaying()){
holder.plays.setImageResource(R.drawable.ic_action_play);
}
ConvertView.setTag(holder);
ConvertView.setOnClickListener(new OnClickListener() {
public void onClick(View v){
Log.d("hi", "hi from "+ pos);
}
});
}
else{
holder = (MyViewHolder)ConvertView.getTag();
}
play = playdata.get(pos);
holder.play = play;
return ConvertView;
}
This is my main activity:
mLastClickedPosition = -1;
this.PlayList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick (AdapterView<?> parent, View view, int position, long id) {
if(mLastClickedPosition != -1){
// do something to pause the item in your list at this position
}
// next, update mLastClickedPosition
mLastClickedPosition = position;
if(position==0){
ImageView imageView = (ImageView) view.findViewById(R.id.plays);
imageView.setImageResource(R.drawable.ic_action_stop);
}
// play audio
}
});
the mediaplayer is initialized in the adapter, I'm not really sure how I'd go about initializing it in the main activity instead. Any help is appreciated! Thanks in advanced!
If each row in the ListView know what state it is in(butten), You could control each row in the ListView using listeners or LocalBroadcastManager. Try this. That is a ListView skeleton to start thinking in OOP where each row really becomes an object that could know what state it is in . A ListView abstraction example that makes it easier to understand/see the java code as objects.
From the example above, let say that every row(EventItem) that are created are a listener or register for LocalBroadcastManager Then it would be easy to address each row. Talk to each row and ask it to stop having the button in a pause state, or whatever
...I'm updating this answer since the link above doesn't work. Here's a new link to a gethub project
listview-with-multiple-layouts
You should follow what Erik suggested and delegate the handling to each row.
BTW, could the problem be because of two listeners you have? You are maintaining the state in main activity which may not even be called. If this is not happening, you may need to move the maintaining state to the list listener (saving the last position).
But, follow what Erik suggested and that should help you to easy debugging and maintenance.
Good Luck.

Do animation after view get displayed in view pager (android)

Hi I am new to android and I am doing one simple application. My application contain one simple activity in witch it contains view pager. my view pager having no of screens 3. SO my view pager working fine. my first and second screen contains one button when i click on that button it will goes to third screen setCurrentItem(2);.
now what i want is when i go third screen it will render one view and few sec only like after completely rendering that view do some animation like flip animation.
what happen in reality when i click on buttons it directly go to that screen but not rendering that default view. it directly starts animation...
My code looks like
public class HelpActivity extends Activity {
private final int NUM_SCREENS = 3;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.help);
mInflater = LayoutInflater.from(this);
vp = (ViewPager) findViewById(R.id.pager);
PagerAdapter pagerAdapter = new MyPagerAdapter();
vp.setAdapter(pagerAdapter);
}
private OnClickListener signin = new OnClickListener() {
#Override
public void onClick(View arg0) {
vp.setCurrentItem(2);
// ******* do some animation on view 3 in pager views ....
}
};
private class MyPagerAdapter extends PagerAdapter {
#Override
public int getCount() {
return NUM_SCREENS;
}
#Override
public Object instantiateItem(View collection, int position) {
View view = null;
Typeface tf = Typeface.createFromAsset(getAssets(),
"fonts/sf_cartoonist_hand_bold.ttf");
if (position == 0) {
// display view1
// on button click call sign in
} else if (position == 1) {
//display view 2
//on button click call sign in
} else if (position == 2) {
//display view 3
}
((ViewPager) collection).addView(view, 0);
return view;
}
}
}
what i need after clicking on button it skips to view3 display for few sec and after that do animation... how to do that?
need help.....
thank you .....
Using Runnable you can hold your animation until your view is not load it properly, you have to measure that in how much seconds your view get load, so you can pass delay as per your view get load time, something like below:
Runnable runnableimage = new Runnable() {
public void run() {
//HERE YOUR ANIMATION
image.startAnimation(animFast);
}
};
It start your animation after 2000 MilliSec
handler.postDelayed(runnableimage, 2000);
Use animate() with start delay:
mView.animate().rotationBy(360).setDuration(3000).setStartDelay(2000).start();

Categories

Resources