Android - 如何为自定义应用实现youtube的用户界面?

时间:2018-02-08 08:57:47

标签: android android-layout android-fragments video android-navigation

我目前正在制作视频直播应用,我希望实现像Youtube这样的用户界面。

注意:我不需要Youtube视频。我想从我的服务器流式传输视频。

我做了一些研究,发现了这个库:Draggablepanel

并尝试添加到我的项目中。这是我的片段布局的代码:

<android.support.design.widget.CoordinatorLayout 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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#000000"
tools:context=".VLCActivity">


<com.github.pedrovgs.DraggableView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:draggable_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/draggable_view"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    draggable_view:top_view_id="@+id/surface"
    draggable_view:bottom_view_id="@+id/bottom"
    draggable_view:top_view_x_scale_factor="@dimen/x_scale_factor"
    draggable_view:top_view_y_scale_factor="@dimen/y_scale_factor"
    draggable_view:top_view_height="@dimen/top_fragment_height"
    draggable_view:top_view_margin_right="@dimen/top_fragment_margin"
    draggable_view:top_view_margin_bottom="@dimen/top_fragment_margin"
    draggable_view:enable_minimized_horizontal_alpha_effect="false"
    draggable_view:top_view_resize="true"
    android:background="@android:color/black">

    <SurfaceView
        android:id="@+id/surface"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true" />

    <FrameLayout
        android:id="@+id/bottom"
        android:layout_width="match_parent"
        android:layout_height="0dp">

    </FrameLayout>


    <ProgressBar
    android:id="@+id/pb"
    style="?android:attr/progressBarStyle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:visibility="gone" />
</com.github.pedrovgs.DraggableView>

<include
    android:id="@+id/include"
    layout="@layout/actionbar_video_chat"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:visibility="visible"></include>

和Java代码:

public class VLCFragment extends Fragment implements IVLCVout.Callback {




private SurfaceView mSurface;
private SurfaceHolder holder;
private LibVLC libvlc;
private MediaPlayer mMediaPlayer = null;
private int mVideoWidth;
private int mVideoHeight;

public int mHeight;
public int mWidth;

ProgressBar pb;

Toolbar vToolbar;

ImageView back,close;

DraggableView draggableView;



private String mFilePath ="rtmp://184.72.239.149/vod/mp4:bigbuckbunny_1500.mp4";


public VLCFragment() {
    // Required empty public constructor
}


public static VLCFragment newInstance()
{
    return new VLCFragment();
}



@Override
public void onAttach(Context context) {
    super.onAttach(context);
    DisplayMetrics displayMetrics = new DisplayMetrics();
    getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
    mHeight = displayMetrics.heightPixels;
    mWidth = displayMetrics.widthPixels;

}

@Override
public void onStart()
{
    super.onStart();


    createPlayer(mFilePath);

}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view =  inflater.inflate(R.layout.fragment_vlc, container, false);

    vToolbar = view.findViewById(R.id.videotoolbar);

    draggableView = view.findViewById(R.id.draggable_view);




    mSurface = view.findViewById(R.id.surface);

    holder = mSurface.getHolder();

    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    pb = view.findViewById(R.id.pb);

    pb.setVisibility(View.VISIBLE);


    back = view.findViewById(R.id.room_back);

    back.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            draggableView.minimize();

            //getActivity().onBackPressed();
        }
    });




    return view;

}


@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);


    draggableView.maximize();

}

/**
 * Used to set size for SurfaceView
 *
 * @param width
 * @param height
 */
private void setSize(int width, int height) {


    mVideoWidth = width;
    mVideoHeight = height;
    if (mVideoWidth * mVideoHeight <= 1)
        return;

    if (holder == null || mSurface == null)
        return;

    int w = getActivity().getWindow().getDecorView().getWidth();
    int h = getActivity().getWindow().getDecorView().getHeight();
    boolean isPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
    if (w > h && isPortrait || w < h && !isPortrait) {
        int i = w;
        w = h;
        h = i;
    }

    float videoAR = (float) mVideoWidth / (float) mVideoHeight;
    float screenAR = (float) w / (float) h;

    if (screenAR < videoAR)
        h = (int) (w / videoAR);
    else
        w = (int) (h * videoAR);

    holder.setFixedSize(mVideoWidth, mVideoHeight);
    ViewGroup.LayoutParams lp = mSurface.getLayoutParams();
    lp.width = w;
    lp.height = h;

    mSurface.setLayoutParams(lp);
    mSurface.invalidate();
    pb.setVisibility(View.INVISIBLE);
}

/**
 * Creates MediaPlayer and plays video
 *
 * @param media
 */
private void createPlayer(String media)
{
    //releasePlayer();
    try {
        if (media.length() > 0) {
            Toast toast = Toast.makeText(getActivity(), media, Toast.LENGTH_LONG);
            toast.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0,
                    0);
            toast.show();
        }

        // Create LibVLC
        // TODO: make this more robust, and sync with audio demo
        ArrayList<String> options = new ArrayList<String>();
        //options.add("--subsdec-encoding <encoding>");
        options.add("--aout=opensles");
        options.add("--audio-time-stretch"); // time stretching
        options.add("-vvv"); // verbosity

        libvlc = new LibVLC(getActivity(), options);
        holder.setKeepScreenOn(true);

        // Creating media player
        mMediaPlayer = new MediaPlayer(libvlc);
        mMediaPlayer.setEventListener(mPlayerListener);

        // Seting up video output
        final IVLCVout vout = mMediaPlayer.getVLCVout();
        vout.setVideoView(mSurface);
        vout.setWindowSize(mWidth,mHeight);
        vout.addCallback(this);
        vout.attachViews();

        Media m = new Media(libvlc, Uri.parse(media));

        mMediaPlayer.setMedia(m);

        mMediaPlayer.play();

    } catch (Exception e) {
        pb.setVisibility(View.INVISIBLE);
        Toast.makeText(getActivity(), "Error in creating player!", Toast
                .LENGTH_LONG).show();

    }
}



private void releasePlayer()
{
    if (libvlc == null)
        return;
    mMediaPlayer.stop();
    final IVLCVout vout = mMediaPlayer.getVLCVout();
    vout.removeCallback(this);
    vout.detachViews();
    holder = null;
    libvlc.release();
    libvlc = null;

    mVideoWidth = 0;
    mVideoHeight = 0;
}

/**
 * Registering callbacks
 */
private MediaPlayer.EventListener mPlayerListener = new MyPlayerListener(this);

@Override
public void onNewLayout(IVLCVout vout, int width, int height, int visibleWidth, int visibleHeight, int sarNum, int sarDen) {
    if (width * height == 0)
        return;

    // store video size
    mVideoWidth = width;
    mVideoHeight = height;
    setSize(mVideoWidth, mVideoHeight);
}

@Override
public void onSurfacesCreated(IVLCVout vout) {

}

@Override
public void onSurfacesDestroyed(IVLCVout vout) {

}

@Override
public void onHardwareAccelerationError(IVLCVout vlcVout) {
    //Log.e(TAG, "Error with hardware acceleration");
    this.releasePlayer();
    Toast.makeText(getActivity(), "Error with hardware acceleration", Toast.LENGTH_LONG).show();
}

private static class MyPlayerListener implements MediaPlayer.EventListener {
    private WeakReference<VLCFragment> mOwner;

    public MyPlayerListener(VLCFragment owner) {

        mOwner = new WeakReference<VLCFragment>(owner);
    }

    @Override
    public void onEvent(MediaPlayer.Event event) {
        VLCFragment player = mOwner.get();

        switch (event.type) {
            case MediaPlayer.Event.EndReached:
               // Log.d(TAG, "MediaPlayerEndReached");
                player.releasePlayer();
                break;
            case MediaPlayer.Event.Playing:
            case MediaPlayer.Event.Paused:
            case MediaPlayer.Event.Stopped:
            default:
                break;
        }
    }
}

@Override
public void onResume()
{
    super.onResume();

    draggableView.maximize();

}

@Override
public void onPause()
{
    super.onPause();


    releasePlayer();

}

@Override
public void onDetach()
{
    super.onDetach();
    releasePlayer();
}
private void startVideo() {
    if (!mMediaPlayer.isPlaying()) {
        mMediaPlayer.play();
    }
}
private void pauseVideo() {
    if (mMediaPlayer.isPlaying()) {
        mMediaPlayer.pause();
    }
}

}

我有一个名为GlobalScreen的活动,它包含一个tabview,每个标签都是一个片段,显示为here。我有一个名为Roomsfragment的片段,里面有一个recyclerview。单击某个项目应该转到包含VLC播放器的片段以流式传输视频。通过这个当前的实现,我能够实现this

到目前为止,我尝试了什么:

  • 首先尝试在android oreo中引入Pictureinpicture模式。但该方法似乎在Android N及以下版本中无效。

  • 接下来尝试在没有draggableview库的情况下通过在Roomsfragment xml中添加一个名为preview的framelayout并在开始时隐藏它来实现此目的。对于视频屏幕,我首先创建了一个活动,并在那里添加了一个片段来播放视频。我使用startactivityforresult()方法开始了这个活动。当我按下视频播放器活动的后退按钮时,我会回到上一个屏幕,在onActivityResult()中,我会使预览布局可见,并用相同的视频片段替换它。但是初始化vlc播放器有一个延迟,所以决定改变它以获得更好的用户体验。

  • 让像Youtube或bigo live app这样的用户界面感觉合适,所以使用了Draggablepanel库。对于这个方法,我删除了我在上一步中所做的修改,并使用Globalactivity的片段管理器替换了这个屏幕本身的片段。但是现在当draggableview最小化时,我无法看到像Youtube之前的屏幕内容。不知道如何从这里开始或实现其他方法。

1 个答案:

答案 0 :(得分:-2)

遵循此github link ...猜测。这就是您要寻找的...

完整的YouTuDraggingView类如下:

public class YouTuDraggingView extends RelativeLayout implements View.OnClickListener {

static final int STATUS_MAX = 1;
static final int STATUS_MIN = 0;
static final int STATUS_DRAG = 2;

interface Callback {
    void onVideoViewHide();

    void videoSize(int width, int height);

    void onIconClick(IconType iconType);

    void status(int status);
}


enum IconType {
    PAUSE,
    PLAY,
    CLOSE
}

Callback mCallback;
IconType statusType = IconType.PLAY;

// Draggable view and details below View
DispatchLayout mBackgroundView;
View mDetailView;
View titleLayout;
View pauseIv;
View closeIv;
View pauseLayout;
View closeLayout;
View mTopView;
Activity mActivity;

MarginViewWrapper mBackgroundViewWrapper;

MarginViewWrapper mTopViewWrapper;
MarginViewWrapper titleWrapper;
MarginViewWrapper pauseIvWrapper;
MarginViewWrapper closeIvWrapper;


float mRangeScrollY;
float mRangeNodeScrollY;

//Current ratio
float nowStateScale;


float MIN_RATIO_HEIGHT_NODE = 0.40f;

static float MIN_RATIO_HEIGHT = 0.30f;
float MIN_RATIO_WIDTH = 0.95f;

static final float VIDEO_RATIO = 16f / 9f;
int finalVideoLeftRightOffset;

//Original width of the video layout
float mTopViewOriginalWidth;
//The original height of the video layout
float mTopOriginalHeight;
float mBackgroundOriginalHeight;

//Bottom distance
float bottomHeight = DensityUtil.dip2px(getContext(), 80);
long rangeDuration = 350;
long dismissDuration = 100;

boolean activityFullscreen = false;
OrientationEventListener mOrientationListener;
private int isRotate;//0 Representing direction lock,1 Represents no direction lock
private long orientationListenerDelayTime = 0;
static boolean isPortraitToLandscape = false;
static boolean isLandscapeToPortrait = false;

public YouTuDraggingView(Context context) {
    this(context, null);
}

public YouTuDraggingView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public YouTuDraggingView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}


private void init() {
    mActivity = getActivityFromView(this);
    activityFullscreen = (mActivity.getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == WindowManager.LayoutParams.FLAG_FULLSCREEN;
    addView(LayoutInflater.from(getContext()).inflate(R.layout.youtu_dispatch, null), 0);
    mBackgroundView = findViewById(R.id.backgroundView);
    mTopView = findViewById(R.id.videoView);
    View videoParentLayout = findViewById(R.id.videoParentLayout);
    mDetailView = findViewById(R.id.scroll_view);

    titleLayout = findViewById(R.id.titleLayout);
    pauseLayout = findViewById(R.id.pauseLayout);
    closeLayout = findViewById(R.id.closeLayout);
    pauseIv = findViewById(R.id.pauseIv);
    closeIv = findViewById(R.id.closeIv);
    pauseIv.setBackgroundResource(R.drawable.pause);
    mBackgroundView.setParentView(this);
    setBackgroundColor(Color.BLACK);
    mBackgroundView.setOnClickListener(this);
    pauseLayout.setOnClickListener(this);
    closeLayout.setOnClickListener(this);
    videoParentLayout.setOnClickListener(this);


    //Initialize the wrapper class
    mBackgroundViewWrapper = new MarginViewWrapper(mBackgroundView);
    mTopViewWrapper = new MarginViewWrapper(mTopView);
    titleWrapper = new MarginViewWrapper(titleLayout);
    pauseIvWrapper = new MarginViewWrapper(pauseLayout);
    closeIvWrapper = new MarginViewWrapper(closeLayout);

    initData();
}


private void initOrientationListener() {
    if (mOrientationListener != null) {
        return;
    }
    mOrientationListener = new OrientationEventListener(mActivity) {
        @Override
        public void onOrientationChanged(int orientation) {
            try {
                //Get open system
                isRotate = Settings.System.getInt(getContext().getContentResolver(), Settings.System.ACCELEROMETER_ROTATION);
            } catch (Settings.SettingNotFoundException e) {
                e.printStackTrace();
            }
            if (isRotate == 0) return;
            if ((orientation >= 300 || orientation <= 30) && System.currentTimeMillis() - orientationListenerDelayTime > 1000) {
                if (isLandscapeToPortrait) {
                    isLandscapeToPortrait = false;
                    mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
                }
                orientationListenerDelayTime = System.currentTimeMillis();
            } else if (orientation >= 260 && orientation <= 280
                    && System.currentTimeMillis() - orientationListenerDelayTime > 1000) {
                if (isPortraitToLandscape) {
                    isPortraitToLandscape = false;
                    mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
                }
                orientationListenerDelayTime = System.currentTimeMillis();
            } else if (orientation >= 70 && orientation <= 90
                    && System.currentTimeMillis() - orientationListenerDelayTime > 1000) {
                if (isPortraitToLandscape) {
                    isPortraitToLandscape = false;
                    mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
                }
                orientationListenerDelayTime = System.currentTimeMillis();
            }
        }
    };
    if (mOrientationListener.canDetectOrientation()) {
        mOrientationListener.enable();
    } else {
        mOrientationListener.disable();
    }

}

private void initData() {
    initOrientationListener();
    //Current zoom ratio
    nowStateScale = 1f;

    if (isLandscape()) {
        mTopViewOriginalWidth = DensityUtil.getScreenW(getContext());
        if (activityFullscreen) {
            mTopOriginalHeight = DensityUtil.getScreenH(getContext());
        } else {
            mTopOriginalHeight = DensityUtil.getScreenH(getContext()) - DensityUtil.getStatusBarH(getContext());
        }
        MIN_RATIO_HEIGHT_NODE = 0.35f;
        MIN_RATIO_HEIGHT = 0.25f;
        mDetailView.setVisibility(View.GONE);
    } else {
        mTopViewOriginalWidth = mBackgroundView.getContext().getResources().getDisplayMetrics().widthPixels;
        mTopOriginalHeight = (mTopViewOriginalWidth / VIDEO_RATIO);
        mDetailView.setVisibility(View.VISIBLE);
    }


    mTopViewWrapper.setHeight(mTopOriginalHeight);
    mTopViewWrapper.setWidth(mTopViewOriginalWidth);

    if (MIN_RATIO_HEIGHT_NODE < MIN_RATIO_HEIGHT) {
        throw new RuntimeException("MIN_RATIO_HEIGHT_NODE can't smaller than MIN_RATIO_HEIGHT_NODE");
    }
}

public Boolean isLandscape() {
    return getContext().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    resetRangeAndSize();
}


public void resetRangeAndSize() {
    mTopViewOriginalWidth = DensityUtil.getScreenW(getContext());
    if (isLandscape()) {
        mTopOriginalHeight = activityFullscreen ? DensityUtil.getScreenH(getContext()) : DensityUtil.getScreenOriginH(getContext());
        MIN_RATIO_HEIGHT_NODE = 0.35f;
        MIN_RATIO_HEIGHT = 0.25f;
        mDetailView.setVisibility(View.GONE);
    } else {
        mTopOriginalHeight = (mTopViewOriginalWidth / VIDEO_RATIO);
        MIN_RATIO_HEIGHT_NODE = 0.45f;
        MIN_RATIO_HEIGHT = 0.35f;
    }
    float height = activityFullscreen ? DensityUtil.getScreenH(getContext()) : DensityUtil.getScreenOriginH(getContext());
    mRangeScrollY = height - MIN_RATIO_HEIGHT * mTopOriginalHeight - bottomHeight;
    mRangeNodeScrollY = height - MIN_RATIO_HEIGHT_NODE * mTopOriginalHeight - bottomHeight;
    mBackgroundOriginalHeight = height;
    finalVideoLeftRightOffset = (int) ((mTopViewOriginalWidth - mTopViewOriginalWidth * MIN_RATIO_WIDTH) / 2);
}

void notifyStatus() {
    if (statusType == IconType.PLAY) {
        statusType = IconType.PAUSE;
        pauseIv.setBackgroundResource(R.drawable.play);
        mCallback.onIconClick(IconType.PAUSE);
    } else {
        statusType = IconType.PLAY;
        pauseIv.setBackgroundResource(R.drawable.pause);
        mCallback.onIconClick(IconType.PLAY);
    }
}

void changeStatus(IconType iconType) {
    if (iconType == IconType.PLAY) {
        statusType = IconType.PAUSE;
        pauseIv.setBackgroundResource(R.drawable.play);
    } else if (iconType == IconType.PAUSE) {
        statusType = IconType.PLAY;
        pauseIv.setBackgroundResource(R.drawable.pause);
    }
}

void updateDismissView(int m) {
    ViewGroup.LayoutParams params = getLayoutParams();
    params.width = -1;
    params.height = -1;
    setLayoutParams(params);
    float fullY = mRangeScrollY + mTopOriginalHeight * MIN_RATIO_HEIGHT;
    float offset = mRangeScrollY;
    if (m < fullY && m > mRangeScrollY) {
        offset = mRangeScrollY + (m - mRangeScrollY);
    }
    if (m >= fullY) {
        offset = fullY;
    }
    if (m < mRangeScrollY) {
        offset = mRangeScrollY;
    }
    float alphaPercent = (m - mRangeScrollY) / (fullY - mRangeScrollY);
    mBackgroundViewWrapper.setMarginTop(Math.round(offset));
    mBackgroundViewWrapper.setMarginBottom(Math.round(bottomHeight - (m - mRangeScrollY)));
    mBackgroundView.setAlpha((1 - alphaPercent));
}

void updateVideoView(int m) {
    if (mBackgroundViewWrapper.getMarginTop() > 0) {
        mCallback.status(STATUS_DRAG);
    }
    //If the current state is minimized,First set our layout width to MATCH_PARENT
    if (nowStateScale == MIN_RATIO_HEIGHT) {
        ViewGroup.LayoutParams params = getLayoutParams();
        params.width = -1;
        params.height = -1;
        setLayoutParams(params);
    }

    //marginTop The maximum value is allScrollY, the minimum is 0
    if (m > mRangeScrollY)
        m = (int) mRangeScrollY;
    if (m < 0)
        m = 0;


    //The percentage of the video view height 100% - 0%
    float marginPercent = (mRangeScrollY - m) / mRangeScrollY;
    float nodeMarginPercent = (mRangeNodeScrollY - m) / mRangeNodeScrollY;

    float videoNodeWidthPercent = MIN_RATIO_WIDTH + (1f - MIN_RATIO_WIDTH) * nodeMarginPercent;
    float videoNodeHeightPercent = MIN_RATIO_HEIGHT_NODE + (1f - MIN_RATIO_HEIGHT_NODE) * nodeMarginPercent;
    float detailPercent = m / mRangeNodeScrollY;


    int videoLeftRightOffset = (int) ((mTopViewOriginalWidth - mTopViewOriginalWidth * videoNodeWidthPercent) / 2);
    int detailBottomOffset = Math.round(bottomHeight * detailPercent);
    //Cannot exceed the bottom spacing
    if (detailBottomOffset >= bottomHeight) {
        detailBottomOffset = Math.round(bottomHeight);
    }
    if (m >= mRangeNodeScrollY) {
        mDetailView.setVisibility(View.GONE);
        float alphaPercent = (m - mRangeNodeScrollY) / (mRangeScrollY - mRangeNodeScrollY);
        //Background moving height
        float offHeight = Math.round(mBackgroundOriginalHeight * MIN_RATIO_HEIGHT_NODE - (m - mRangeNodeScrollY));
        //Video View's moving height
        float offHeight2 = Math.round(mTopOriginalHeight * MIN_RATIO_HEIGHT_NODE - (m - mRangeNodeScrollY));
        mBackgroundViewWrapper.setMarginTop(m);
        mBackgroundViewWrapper.setHeight(offHeight);
        float videoRightOffset = (m - mRangeNodeScrollY) / (mRangeScrollY - mRangeNodeScrollY) * mTopViewOriginalWidth * MIN_RATIO_WIDTH * 2 / 3;
        float topViewWidth = Math.round(mTopViewOriginalWidth * MIN_RATIO_WIDTH - videoRightOffset);

        mTopViewWrapper.setHeight(offHeight2);
        mTopViewWrapper.setWidth(topViewWidth);

        //The width of the slide when the head reaches the minimum width
        float pieceWidth = mTopViewOriginalWidth * MIN_RATIO_WIDTH / 3;
        float minWidthOffset = topViewWidth - pieceWidth;
        float imageLayoutWidth = pieceWidth / 2;

        //Control position at minimum layout
        float titleWidth = pieceWidth - minWidthOffset;
        float pauseWidth = imageLayoutWidth;
        float closeWidth = imageLayoutWidth;
        float pauseLeftOffset = pieceWidth - minWidthOffset;
        float closeLeftOffset = pieceWidth + pieceWidth / 2 - minWidthOffset;
        if (minWidthOffset >= pieceWidth) {
            titleWidth = 0;
            pauseLeftOffset = 0;
            pauseWidth = imageLayoutWidth - minWidthOffset + pieceWidth;
        }
        if (minWidthOffset >= pieceWidth + imageLayoutWidth) {
            pauseWidth = 0;
            closeLeftOffset = 0;
            closeWidth = imageLayoutWidth - minWidthOffset + pieceWidth + imageLayoutWidth;
        }
        if (minWidthOffset >= pieceWidth * 2) {
            closeWidth = 0;
        }

        titleWrapper.setWidth(Math.round(titleWidth));
        titleWrapper.setHeight(offHeight2);

        pauseIvWrapper.setWidth(Math.round(pauseWidth));
        pauseIvWrapper.setHeight(offHeight2);
        pauseIvWrapper.setMarginLeft(Math.round(pauseLeftOffset));


        closeIvWrapper.setWidth(closeWidth);
        closeIvWrapper.setHeight(offHeight2);
        closeIvWrapper.setMarginLeft(Math.round(closeLeftOffset));

        pauseIv.setAlpha(alphaPercent);
        closeIv.setAlpha(alphaPercent);
        titleLayout.setAlpha(alphaPercent);
    } else {
        mDetailView.setVisibility(View.VISIBLE);
        mBackgroundViewWrapper.setHeight(Math.round(mBackgroundOriginalHeight * videoNodeHeightPercent));
        mTopViewWrapper.setWidth(Math.round(mTopViewOriginalWidth * videoNodeWidthPercent));
        mTopViewWrapper.setHeight(Math.round(mTopOriginalHeight * videoNodeHeightPercent));

        mBackgroundViewWrapper.setMarginTop(m);
    }
    mBackgroundViewWrapper.setWidth(Math.round(mTopViewOriginalWidth * videoNodeWidthPercent));
    mBackgroundViewWrapper.setMarginRight(videoLeftRightOffset);
    mBackgroundViewWrapper.setMarginLeft(videoLeftRightOffset);
    mBackgroundViewWrapper.setMarginBottom(detailBottomOffset);
    mDetailView.setAlpha(marginPercent);
    this.getBackground().setAlpha((int) (marginPercent * 255 * 0.6f));
    mCallback.videoSize(mTopViewWrapper.getWidth(), mTopViewWrapper.getHeight());
    mBackgroundView.setAlpha(1);
}

void dismissView() {
    float fullY = mRangeScrollY + mTopOriginalHeight * MIN_RATIO_HEIGHT;
    AnimatorSet set = new AnimatorSet();
    set.playTogether(ObjectAnimator.ofFloat(mBackgroundView, "alpha", 1f, 0),
            ObjectAnimator.ofInt(mBackgroundViewWrapper, "marginTop",
                    mBackgroundViewWrapper.getMarginTop(), Math.round(fullY)));
    set.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            setVisibility(INVISIBLE);
            mBackgroundView.setAlpha(1f);
        }
    });
    set.setDuration((long) (dismissDuration * mBackgroundViewWrapper.getMarginTop() / fullY)).start();

    if (mCallback != null)
        mCallback.onVideoViewHide();
}

void confirmState(float v, int dy) {
    if (mBackgroundViewWrapper.getMarginTop() >= mRangeScrollY) {
        if (v > 15) {
            dismissView();
        } else {
            goMin(true);
        }

    } else {
        //Dy is used to judge whether the direction is sliding in the opposite direction.
        //Change the state if the width reaches a certain value when the finger is raised or the speed reaches a certain value.
        if (nowStateScale == 1f) {
            if (mTopViewOriginalWidth - mBackgroundView.getWidth() >= mTopViewOriginalWidth * (1 - MIN_RATIO_WIDTH) / 3 || (v > 5 && dy > 0)) {
                goMin();
            } else {
                goMax();
            }
        } else {
            if (mTopViewOriginalWidth - mBackgroundView.getWidth() <= 2 * mTopViewOriginalWidth * (1 - MIN_RATIO_WIDTH) / 3 || (v > 5 && dy < 0)) {
                goMax();
            } else {
                goMin();
            }
        }
    }
}

public void fullScreenGoMin() {
    if (isLandscape()) {
        nowStateScale = MIN_RATIO_HEIGHT;
        if (!activityFullscreen) {
            mActivity.getWindow().clearFlags(
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
        }

        resetRangeAndSize();
        mBackgroundViewWrapper.setMarginTop(Math.round(mRangeScrollY));
        updateVideoView(Math.round(mRangeScrollY));
    } else {
        goMin();
    }
}

public void goLandscapeMin() {
    mCallback.status(STATUS_MIN);
    nowStateScale = MIN_RATIO_HEIGHT;
    resetRangeAndSize();
    mBackgroundViewWrapper.setMarginTop(Math.round(mRangeScrollY));
    updateVideoView(Math.round(mRangeScrollY));
}

public void goPortraitMin() {
    nowStateScale = MIN_RATIO_HEIGHT;
    mCallback.status(STATUS_MIN);
    resetRangeAndSize();
    mBackgroundViewWrapper.setMarginTop(Math.round(mRangeScrollY));
    updateVideoView(Math.round(mRangeScrollY));
}

public void goPortraitMax() {
    if (!activityFullscreen) {
        mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

    }
    mCallback.status(STATUS_MAX);
    nowStateScale = 1f;
    resetRangeAndSize();
    mBackgroundViewWrapper.setMarginTop(0);
    updateVideoView(0);
}

public void goFullScreen() {
    if (!activityFullscreen) {
        mActivity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

    }

    mCallback.status(STATUS_MAX);
    mBackgroundViewWrapper.setWidth(DensityUtil.getScreenW(getContext()));
    mBackgroundViewWrapper.setHeight(DensityUtil.getScreenH(getContext()));
    mTopViewWrapper.setWidth(DensityUtil.getScreenW(getContext()));
    mTopViewWrapper.setHeight(DensityUtil.getScreenH(getContext()));
    mCallback.videoSize(mTopViewWrapper.getWidth(), mTopViewWrapper.getHeight());
}

public void goMax() {
    if (nowStateScale == MIN_RATIO_HEIGHT) {
        MangalStuti.toolbar.setVisibility(GONE);
        YoutubeControlPanel.openYouTube.setVisibility(VISIBLE);
        YoutubeControlPanel.downIv.setVisibility(VISIBLE);
        YoutubeControlPanel.total.setVisibility(VISIBLE);
        YoutubeControlPanel.current.setVisibility(VISIBLE);
        ViewGroup.LayoutParams params = getLayoutParams();
        params.width = -1;
        params.height = -1;
        setLayoutParams(params);
    }


    ValueAnimator valueAnimator = ValueAnimator.ofFloat(mBackgroundViewWrapper.getMarginTop(), 0);
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float value = (float) animation.getAnimatedValue();

            updateVideoView((int) value);
            if (value == 0) {
                if (isLandscape()) {
                    goFullScreen();
                }
                mCallback.status(STATUS_MAX);
            }
        }
    });
    valueAnimator.setDuration((long) (mBackgroundViewWrapper.getMarginTop() / mRangeScrollY * rangeDuration)).start();

    nowStateScale = 1.0f;
}


public void goMin() {
    goMin(false);
}

public void goMin(final boolean isDismissToMin) {
    MangalStuti.toolbar.setVisibility(VISIBLE);
    nowStateScale = MIN_RATIO_HEIGHT;
    YoutubeControlPanel.openYouTube.setVisibility(INVISIBLE);
    YoutubeControlPanel.downIv.setVisibility(INVISIBLE);
    YoutubeControlPanel.total.setVisibility(INVISIBLE);
    YoutubeControlPanel.current.setVisibility(INVISIBLE);
    final float fullTop = Math.abs(mBackgroundViewWrapper.getMarginTop() - mRangeScrollY);
    ValueAnimator valueAnimator = ValueAnimator.ofFloat(mBackgroundViewWrapper.getMarginTop(), mRangeScrollY);
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float value = (float) animation.getAnimatedValue();
            mBackgroundView.setAlpha(isDismissToMin ? (value / fullTop) : 1);
            updateVideoView((int) value);
            if (value == mRangeScrollY) {
                ViewGroup.LayoutParams p = getLayoutParams();
                p.width = -2;
                p.height = -2;
                setLayoutParams(p);
                mCallback.status(STATUS_MIN);
            }
        }
    });
    valueAnimator.setDuration((long) (Math.abs((1 - mBackgroundViewWrapper.getMarginTop() / mRangeScrollY)) * rangeDuration)).start();
}


//Get current status
public float getNowStateScale() {
    return nowStateScale;
}

public boolean isMin() {
    return nowStateScale == MIN_RATIO_HEIGHT;
}

public boolean isMax() {
    return nowStateScale == 1f;
}

public void show() {
    setVisibility(VISIBLE);
    statusType = IconType.PLAY;
    pauseIv.setBackgroundResource(R.drawable.pause);
    //The default is to change from the bottom to the top.
    mBackgroundViewWrapper.setMarginTop((int) mRangeScrollY);
    goMax();
}

public void setCallback(Callback callback) {
    mCallback = callback;
}

class MarginViewWrapper {
    private ViewGroup.MarginLayoutParams params;
    private View viewWrapper;

    MarginViewWrapper(View view) {
        this.viewWrapper = view;
        params = (ViewGroup.MarginLayoutParams) viewWrapper.getLayoutParams();
        if (params instanceof LinearLayout.LayoutParams) {
            ((LinearLayout.LayoutParams) params).gravity = Gravity.START;
        }
    }


    int getWidth() {
        return params.width < 0 ? (int) mTopViewOriginalWidth : params.width;
    }

    int getHeight() {
        return params.height < 0 ? (int) mTopOriginalHeight : params.height;
    }

    void setWidth(float width) {
        if (width == mTopViewOriginalWidth) {
            params.width = -1;
            params.setMargins(0, 0, 0, 0);
        } else
            params.width = (int) width;

        viewWrapper.setLayoutParams(params);
    }

    void setHeight(float height) {
        params.height = (int) height;
        viewWrapper.setLayoutParams(params);
    }

    void setMarginTop(int m) {
        params.topMargin = m;
        viewWrapper.setLayoutParams(params);
    }

    void setMarginBottom(int m) {
        params.bottomMargin = m - MangalStuti.actionBarHeight;
        viewWrapper.setLayoutParams(params);
    }

    int getMarginTop() {
        return params.topMargin;
    }

    void setMarginRight(int mr) {
        params.rightMargin = mr;
        viewWrapper.setLayoutParams(params);
    }

    void setMarginLeft(int mr) {
        params.leftMargin = mr;
        viewWrapper.setLayoutParams(params);
    }

    int getMarginRight() {
        return params.rightMargin;
    }

    int getMarginLeft() {
        return params.leftMargin;
    }

    int getMarginBottom() {
        return params.bottomMargin;
    }
}

public static Activity getActivityFromView(View view) {
    if (null != view) {
        Context context = view.getContext();
        while (context instanceof ContextWrapper) {
            if (context instanceof Activity) {
                return (Activity) context;
            }
            context = ((ContextWrapper) context).getBaseContext();
        }
    }
    return null;
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.videoParentLayout:
            if (nowStateScale == MIN_RATIO_HEIGHT) {
                goMax();
            }
            break;
        case R.id.downIv:
            fullScreenGoMin();
            break;
        case R.id.pauseLayout:
            if (MediaPlayerManager.instance().getPlayerState() == MediaPlayerManager.PlayerState.ERROR ||
                    MediaPlayerManager.instance().getPlayerState() == MediaPlayerManager.PlayerState.PREPARING) {
                return;
            }
            notifyStatus();
            break;
        case R.id.closeLayout:
            dismissView();
            mCallback.onIconClick(YouTuDraggingView.IconType.CLOSE);
            break;
        case R.id.statusIv:
            notifyStatus();
            break;
    }
}


void fullScreenChange() {
    if (isLandscape()) {
        isLandscapeToPortrait = true;
        mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
    } else {
        isPortraitToLandscape = true;
        mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
    }
}

boolean handleKeyDown(int keyCode) {
    if (keyCode == KeyEvent.KEYCODE_BACK && getNowStateScale() == 1f) {
        if (isPortraitToLandscape) {
            mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
            goPortraitMax();
        } else if (isLandscape()) {
            fullScreenGoMin();
        } else {
            goMin();
        }
        return true;
    }
    return false;
}

public void e(String msg) {
    Log.e("Youtu", msg);
}

@Override
protected void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        //The current screen is landscape
        if (getNowStateScale() == 1f) {
            goFullScreen();
        } else {
            goLandscapeMin();
        }

    } else {
        //The current screen is a vertical screen
        if (getNowStateScale() == 1f) {
            goPortraitMax();
        } else {
            goPortraitMin();
        }
    }
}
}

在“视频活动”的onCreate方法中,添加以下行:

mVideoView = findViewById(R.id.videoView);
mYouTuDraggingView = findViewById(R.id.youtube_view);
mYouTuDraggingView.setCallback(this);
playVideo();

您的playVideo方法..

private void playVideo() {
mYouTuDraggingView.show();
mVideoView.setUp("https://github.com/moyokoo/Media/blob/master/Azshara.mp4?raw=true");  // edit it with your video link
mVideoView.start();
MediaPlayerManager.instance().setScreenScale(ScaleType.SCALE_CENTER_CROP);
}

还如下更改xml中的videoView

<com.example.m.youtu.YouTuDraggingView
    android:id="@+id/your_video_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="bottom"
    android:orientation="vertical"
    android:visibility="invisible"/>

简而言之,您要查找的方法是goMin();类的goMax();YoutuDraggingView