Multiple YouTubePlayerFragments inside a Horizonta

2020-02-06 17:05发布

问题:

I want to show multiple YouTube videos in a Horizontal ScrollView. For that, I'm adding YouTubePlayerFragments dynamically. Here's the piece of my code:

 //set videos

    int count = 0;
    FragmentTransaction transaction = getChildFragmentManager().beginTransaction();

    for (final Video video : mVideos) {

        //create an instance of a video fragment
        final VideoFragment fragment = new VideoFragment();// VideoFragment extends YouTubePlayerFragment
        Bundle bundle = new Bundle();
        if (null != mVideos && 0 < mVideos.size()) {
            bundle.putString(VideoFragment.KEY_VIDEO_KEY, video.getKey());
        }
        fragment.setArguments(bundle);

        FrameLayout frameLayout = new FrameLayout(getActivity());
        frameLayout.setLayoutParams(new FrameLayout.LayoutParams(900, 500));
        frameLayout.setPadding(10, 0, 10, 0);
        frameLayout.setId(12345 + ++count);
        mLayoutTrailers.addView(frameLayout);//mLayoutTrailers is a LinearLayout inside my Horizontal ScrollView

        transaction.add(frameLayout.getId(), fragment, VideoFragment.TAG + count);
    }

    transaction.commit();

I'm initializing the youtube player inside OnResume of my VideoFragment. And below is how the videos gets loaded.

It shows the lastly loaded video for all the players. I debugged - It initializes all the players with the first video, then all the players with the second video & so on until the last one.

The issue is already discussed here. There seems to be a work around with initializing the player inside "setUserVisibleHint(boolean isVisibleToUser)" in my VideoFragment in stead of OnResume(), but I don't know how to use that with my HorizontalScrollView

Is there a way I can load multiple YouTube videos in a Horizontal ScrollView?

Any sort of help will be appreciated!

回答1:

I dont think it is possible to create multiple instance of YouTube Player Fragment as it is Singleton.

No matter how many instances you make they all gone be same and your horizontal scrollview will show thumbnail of last VideoFragment you added .

Alternatively you can give an illusion of multiple YouTube Fragment by showing video thumb and on click of thumb play the video with the help of youtube player

      // get thumbnail image of that video by videoID
      String videoThumbUrl="http://img.youtube.com/vi/"+videoId+"/0.jpg";

      //Load thumb in viewpager/Hrizontal scrollview/Recycle View with the    
      //help of Picasso/Glide/UIL etc     
      Picasso.with(getActivity())
                    .load(videoThumbUrl) 
                    .into(videoThumbImageView);

And then on click of thumb you can add youtube fragment in View container holding imageview and start playing video with the video id

videoThumbImageView.setOnClickListenr(..)
{...

 //Add Youtube fragment in container and start playing video
}

This is just a pseudo code but you get and idea.

Edit

Added code for how to play and stop videos on tap of thumbnails.

I was offline so was unable to use YouTube fragment so I used Videoview to play random videos you can replace videoview with YouTube fragment and. Guranteed it still gone work great

Array list to hold list of videos

    public static ArrayList<VideoModel> listOfVideos = new ArrayList<>();

Variable to keep track of current playing video

      // Allows to remember the last item shown on screen
        private int lastPosition = 0;

Recycler view item click listener

   videoGridAdapter.setOnCardClickListner(new VideoGridAdapter.OnCardClickListner() {
            @Override
            public void OnCardClicked(View view, int position) {

                //Make Lats Tapped item playing false
                listOfVideos.get(lastPosition).setPlaying(false);

                //Make current Tapped item playing true
                listOfVideos.get(position).setPlaying(true);

                // update pointer of last tapped video to current tapped video
                lastPosition = position;

                //LET RCYCLERVIEW ADAPTER DO THE MAGIC
                videoGridAdapter.notifyDataSetChanged();
            }
        });

VideoModel class

        **
 * Created by Hitesh on 20-07-2016.
 */
public class VideoModel {

    public int getImageURLTest() {
        return imageURLTest;
    }

    //Test Data
    private int imageURLTest;

    //Real Time Data
    private String videoURL;
    private String imageURL;
    private boolean isPlaying;

    public VideoModel(String videoURL, boolean isSelected, int imageURLTest) {
        this.videoURL = videoURL;
        this.isPlaying = isSelected;
        this.imageURLTest = imageURLTest;
    }

    public boolean isPlaying() {
        return isPlaying;
    }

    public void setPlaying(boolean playing) {
        isPlaying = playing;
    }

    /**
     * @return Youtube URl of Video
     */
    public String getVideoURL() {
        return videoURL;
    }

    /**
     * @return Thumbnail of Video using video ID
     */
    public String getImageURL() {
        //Derive Image URl from Video URl using Video ID
        return imageURL;
    }
}

Adpter itself

import android.content.Context;
import android.media.MediaPlayer;
import android.net.Uri;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import com.hiteshsahu.videoinraw.R;
import com.hiteshsahu.videoinraw.ui.activity.VideoGridActivity;
import com.squareup.picasso.Callback;
import com.squareup.picasso.NetworkPolicy;
import com.squareup.picasso.Picasso;

public class VideoGridAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private Context context;

    private OnCardClickListner onCardClickListner;

    public VideoGridAdapter() {

    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                      int viewType) {
        RecyclerView.ViewHolder viewHolder;

        context = parent.getContext();

        // create a new view
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.video_row, parent, false);

        // set the view's size, margins, paddings and layout parameters
        viewHolder = new VideoViewHolder(v);

        return viewHolder;
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
        VideoViewHolder videoHolder = (VideoViewHolder) holder;

        if (VideoGridActivity.listOfVideos.get(position).isPlaying()) {

            //Playing Video :- Show VideoView and make play button GONE
            ((VideoViewHolder) holder).getVideoView().setVisibility(View.VISIBLE);
            ((VideoViewHolder) holder).getPlayButton().setVisibility(View.GONE);

            //Play Video in video View
            ((VideoViewHolder) holder).getVideoView().setVisibility(View.VISIBLE);
            ((VideoViewHolder) holder).getVideoView().setVideoURI(Uri.parse(VideoGridActivity.listOfVideos.get(position).getVideoURL()));
            // MediaControlandroid.widget.VideoView videoView = (VideoView) headerView.findViewById(R.id.vdo_banner);ler md = new MediaController(getActivity());
            ((VideoViewHolder) holder).getVideoView().setMediaController(null);
            ((VideoViewHolder) holder).getVideoView().requestFocus();
            // videoView.setZOrderOnTop(true);
            ((VideoViewHolder) holder).getVideoView().start();
            ((VideoViewHolder) holder).getVideoView().setOnTouchListener(new View.OnTouchListener() {

                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    // TODO Auto-generated method stub
                    return true;
                }
            });

            ((VideoViewHolder) holder).getVideoView().setOnPreparedListener(new MediaPlayer.OnPreparedListener() {

                @Override
                public void onPrepared(MediaPlayer mp) {
                    // TODO Auto-generated method stub
                    mp.setLooping(true);
                }
            });

        } else {

            //Not playing make videoview gone and show play button
            ((VideoViewHolder) holder).getVideoView().setVisibility(View.GONE);
            ((VideoViewHolder) holder).getPlayButton().setVisibility(View.VISIBLE);

        }

        //set thumbnail image using video url
        Picasso.with(context)
                .load(VideoGridActivity.listOfVideos.get(position).getImageURL()).fit().placeholder(VideoGridActivity.listOfVideos.get(position).getImageURLTest())
                .networkPolicy(NetworkPolicy.OFFLINE).fit()
                .centerCrop()
                .into(((VideoViewHolder) holder).getVideoThumb(), new Callback() {
                    @Override
                    public void onSuccess() {
                    }

                    @Override
                    public void onError() {
                        // Try again online if cache failed
                        Picasso.with(context)
                                .load(VideoGridActivity.listOfVideos.get(position).getImageURL()).fit().placeholder(VideoGridActivity.listOfVideos.get(position).getImageURLTest())
                                .centerCrop()
                                .into(((VideoViewHolder) holder).getVideoThumb());
                    }
                });


        ((VideoViewHolder) holder).getContainer().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onCardClickListner.OnCardClicked(v, position);


            }
        });

    }

    @Override
    public int getItemCount() {
        return VideoGridActivity.listOfVideos.size();
    }

    public void setOnCardClickListner(OnCardClickListner onCardClickListner) {
        this.onCardClickListner = onCardClickListner;
    }

    public interface OnCardClickListner {
        void OnCardClicked(View view, int position);
    }

}

Layout activity main

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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:fitsSystemWindows="true"
    tools:context=".ui.activity.VideoGridActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/video_grid"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:foregroundGravity="center"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"></android.support.v7.widget.RecyclerView>
    </RelativeLayout>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_dialog_dialer" />

</android.support.design.widget.CoordinatorLayout>

Recyclerview item

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root_container"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:layout_margin="5dp">


    <ImageView
        android:id="@+id/video_thumb"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitXY" />


    <VideoView
        android:id="@+id/video_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:visibility="gone" />

    <!--Add a mask over video thumbnail with a play button icon-->
    <RelativeLayout
        android:id="@+id/play_button"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#68472986">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_gravity="center"
            android:src="@android:drawable/ic_media_play" />
    </RelativeLayout>

</FrameLayout>