將viewpager改成scrollview
@ -0,0 +1,484 @@
|
||||
package com.ray650128.gstreamer_demo_app.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Display;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Scroller;
|
||||
|
||||
/**
|
||||
* A view group that allows users to switch between multiple screens (layouts) in the same way as
|
||||
* the Android home screen (Launcher application).
|
||||
* <p>
|
||||
* You can add and remove views using the normal methods {@link ViewGroup#addView(View)},
|
||||
* {@link ViewGroup#removeView(View)} etc. You may want to listen for updates by calling
|
||||
* {@link HorizontalPager#setOnScreenSwitchListener(OnScreenSwitchListener)} in order to perform
|
||||
* operations once a new screen has been selected.
|
||||
*
|
||||
* Modifications from original version (ysamlan): Animate argument in setCurrentScreen and duration
|
||||
* in snapToScreen; onInterceptTouchEvent handling to support nesting a vertical Scrollview inside
|
||||
* the RealViewSwitcher; allowing snapping to a view even during an ongoing scroll; snap to
|
||||
* next/prev view on 25% scroll change; density-independent swipe sensitivity; width-independent
|
||||
* pager animation durations on scrolling to properly handle large screens without excessively
|
||||
* long animations.
|
||||
*
|
||||
* Other modifications:
|
||||
* (aveyD) Handle orientation changes properly and fully snap to the right position.
|
||||
*
|
||||
* @author Marc Reichelt, <a href="http://www.marcreichelt.de/">http://www.marcreichelt.de/</a>
|
||||
* @version 0.1.0
|
||||
*/
|
||||
public final class HorizontalPager extends ViewGroup {
|
||||
/*
|
||||
* How long to animate between screens when programmatically setting with setCurrentScreen using
|
||||
* the animate parameter
|
||||
*/
|
||||
private static final int ANIMATION_SCREEN_SET_DURATION_MILLIS = 500;
|
||||
// What fraction (1/x) of the screen the user must swipe to indicate a page change
|
||||
private static final int FRACTION_OF_SCREEN_WIDTH_FOR_SWIPE = 4;
|
||||
private static final int INVALID_SCREEN = -1;
|
||||
/*
|
||||
* Velocity of a swipe (in density-independent pixels per second) to force a swipe to the
|
||||
* next/previous screen. Adjusted into mDensityAdjustedSnapVelocity on init.
|
||||
*/
|
||||
private static final int SNAP_VELOCITY_DIP_PER_SECOND = 600;
|
||||
// Argument to getVelocity for units to give pixels per second (1 = pixels per millisecond).
|
||||
private static final int VELOCITY_UNIT_PIXELS_PER_SECOND = 1000;
|
||||
|
||||
private static final int TOUCH_STATE_REST = 0;
|
||||
private static final int TOUCH_STATE_HORIZONTAL_SCROLLING = 1;
|
||||
private static final int TOUCH_STATE_VERTICAL_SCROLLING = -1;
|
||||
private int mCurrentScreen;
|
||||
private int mDensityAdjustedSnapVelocity;
|
||||
private boolean mFirstLayout = true;
|
||||
private float mLastMotionX;
|
||||
private float mLastMotionY;
|
||||
private OnScreenSwitchListener mOnScreenSwitchListener;
|
||||
private int mMaximumVelocity;
|
||||
private int mNextScreen = INVALID_SCREEN;
|
||||
private Scroller mScroller;
|
||||
private int mTouchSlop;
|
||||
private int mTouchState = TOUCH_STATE_REST;
|
||||
private VelocityTracker mVelocityTracker;
|
||||
private int mLastSeenLayoutWidth = -1;
|
||||
|
||||
/**
|
||||
* Simple constructor to use when creating a view from code.
|
||||
*
|
||||
* @param context The Context the view is running in, through which it can
|
||||
* access the current theme, resources, etc.
|
||||
*/
|
||||
public HorizontalPager(final Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that is called when inflating a view from XML. This is called
|
||||
* when a view is being constructed from an XML file, supplying attributes
|
||||
* that were specified in the XML file. This version uses a default style of
|
||||
* 0, so the only attribute values applied are those in the Context's Theme
|
||||
* and the given AttributeSet.
|
||||
*
|
||||
* <p>
|
||||
* The method onFinishInflate() will be called after all children have been
|
||||
* added.
|
||||
*
|
||||
* @param context The Context the view is running in, through which it can
|
||||
* access the current theme, resources, etc.
|
||||
* @param attrs The attributes of the XML tag that is inflating the view.
|
||||
* @see #View(Context, AttributeSet, int)
|
||||
*/
|
||||
public HorizontalPager(final Context context, final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the scroller and touch/fling sensitivity parameters for the pager.
|
||||
*/
|
||||
private void init() {
|
||||
mScroller = new Scroller(getContext());
|
||||
|
||||
// Calculate the density-dependent snap velocity in pixels
|
||||
DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||
((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
|
||||
.getMetrics(displayMetrics);
|
||||
mDensityAdjustedSnapVelocity =
|
||||
(int) (displayMetrics.density * SNAP_VELOCITY_DIP_PER_SECOND);
|
||||
|
||||
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
|
||||
mTouchSlop = configuration.getScaledTouchSlop();
|
||||
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
final int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
if (widthMode != MeasureSpec.EXACTLY) {
|
||||
throw new IllegalStateException("ViewSwitcher can only be used in EXACTLY mode.");
|
||||
}
|
||||
|
||||
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
if (heightMode != MeasureSpec.EXACTLY) {
|
||||
throw new IllegalStateException("ViewSwitcher can only be used in EXACTLY mode.");
|
||||
}
|
||||
|
||||
// The children are given the same width and height as the workspace
|
||||
final int count = getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
if (mFirstLayout) {
|
||||
scrollTo(mCurrentScreen * width, 0);
|
||||
mFirstLayout = false;
|
||||
}
|
||||
|
||||
else if (width != mLastSeenLayoutWidth) { // Width has changed
|
||||
/*
|
||||
* Recalculate the width and scroll to the right position to be sure we're in the right
|
||||
* place in the event that we had a rotation that didn't result in an activity restart
|
||||
* (code by aveyD). Without this you can end up between two pages after a rotation.
|
||||
*/
|
||||
Display display =
|
||||
((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE))
|
||||
.getDefaultDisplay();
|
||||
int displayWidth = display.getWidth();
|
||||
|
||||
mNextScreen = Math.max(0, Math.min(getCurrentScreen(), getChildCount() - 1));
|
||||
final int newX = mNextScreen * displayWidth;
|
||||
final int delta = newX - getScrollX();
|
||||
|
||||
mScroller.startScroll(getScrollX(), 0, delta, 0, 0);
|
||||
}
|
||||
|
||||
mLastSeenLayoutWidth = width;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(final boolean changed, final int l, final int t, final int r,
|
||||
final int b) {
|
||||
int childLeft = 0;
|
||||
final int count = getChildCount();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() != View.GONE) {
|
||||
final int childWidth = child.getMeasuredWidth();
|
||||
child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());
|
||||
childLeft += childWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(final MotionEvent ev) {
|
||||
/*
|
||||
* By Yoni Samlan: Modified onInterceptTouchEvent based on standard ScrollView's
|
||||
* onIntercept. The logic is designed to support a nested vertically scrolling view inside
|
||||
* this one; once a scroll registers for X-wise scrolling, handle it in this view and don't
|
||||
* let the children, but once a scroll registers for y-wise scrolling, let the children
|
||||
* handle it exclusively.
|
||||
*/
|
||||
final int action = ev.getAction();
|
||||
boolean intercept = false;
|
||||
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
/*
|
||||
* If we're in a horizontal scroll event, take it (intercept further events). But if
|
||||
* we're mid-vertical-scroll, don't even try; let the children deal with it. If we
|
||||
* haven't found a scroll event yet, check for one.
|
||||
*/
|
||||
if (mTouchState == TOUCH_STATE_HORIZONTAL_SCROLLING) {
|
||||
/*
|
||||
* We've already started a horizontal scroll; set intercept to true so we can
|
||||
* take the remainder of all touch events in onTouchEvent.
|
||||
*/
|
||||
intercept = true;
|
||||
} else if (mTouchState == TOUCH_STATE_VERTICAL_SCROLLING) {
|
||||
// Let children handle the events for the duration of the scroll event.
|
||||
intercept = false;
|
||||
} else { // We haven't picked up a scroll event yet; check for one.
|
||||
|
||||
/*
|
||||
* If we detected a horizontal scroll event, start stealing touch events (mark
|
||||
* as scrolling). Otherwise, see if we had a vertical scroll event -- if so, let
|
||||
* the children handle it and don't look to intercept again until the motion is
|
||||
* done.
|
||||
*/
|
||||
|
||||
final float x = ev.getX();
|
||||
final int xDiff = (int) Math.abs(x - mLastMotionX);
|
||||
boolean xMoved = xDiff > mTouchSlop;
|
||||
|
||||
if (xMoved) {
|
||||
// Scroll if the user moved far enough along the X axis
|
||||
mTouchState = TOUCH_STATE_HORIZONTAL_SCROLLING;
|
||||
mLastMotionX = x;
|
||||
}
|
||||
|
||||
final float y = ev.getY();
|
||||
final int yDiff = (int) Math.abs(y - mLastMotionY);
|
||||
boolean yMoved = yDiff > mTouchSlop;
|
||||
|
||||
if (yMoved) {
|
||||
mTouchState = TOUCH_STATE_VERTICAL_SCROLLING;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
// Release the drag.
|
||||
mTouchState = TOUCH_STATE_REST;
|
||||
break;
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
/*
|
||||
* No motion yet, but register the coordinates so we can check for intercept at the
|
||||
* next MOVE event.
|
||||
*/
|
||||
mLastMotionY = ev.getY();
|
||||
mLastMotionX = ev.getX();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return intercept;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(final MotionEvent ev) {
|
||||
|
||||
if (mVelocityTracker == null) {
|
||||
mVelocityTracker = VelocityTracker.obtain();
|
||||
}
|
||||
mVelocityTracker.addMovement(ev);
|
||||
|
||||
final int action = ev.getAction();
|
||||
final float x = ev.getX();
|
||||
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
/*
|
||||
* If being flinged and user touches, stop the fling. isFinished will be false if
|
||||
* being flinged.
|
||||
*/
|
||||
if (!mScroller.isFinished()) {
|
||||
mScroller.abortAnimation();
|
||||
}
|
||||
|
||||
// Remember where the motion event started
|
||||
mLastMotionX = x;
|
||||
|
||||
if (mScroller.isFinished()) {
|
||||
mTouchState = TOUCH_STATE_REST;
|
||||
} else {
|
||||
mTouchState = TOUCH_STATE_HORIZONTAL_SCROLLING;
|
||||
}
|
||||
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
final int xDiff = (int) Math.abs(x - mLastMotionX);
|
||||
boolean xMoved = xDiff > mTouchSlop;
|
||||
|
||||
if (xMoved) {
|
||||
// Scroll if the user moved far enough along the X axis
|
||||
mTouchState = TOUCH_STATE_HORIZONTAL_SCROLLING;
|
||||
}
|
||||
|
||||
if (mTouchState == TOUCH_STATE_HORIZONTAL_SCROLLING) {
|
||||
// Scroll to follow the motion event
|
||||
final int deltaX = (int) (mLastMotionX - x);
|
||||
mLastMotionX = x;
|
||||
final int scrollX = getScrollX();
|
||||
|
||||
if (deltaX < 0) {
|
||||
if (scrollX > 0) {
|
||||
scrollBy(Math.max(-scrollX, deltaX), 0);
|
||||
}
|
||||
} else if (deltaX > 0) {
|
||||
final int availableToScroll =
|
||||
getChildAt(getChildCount() - 1).getRight() - scrollX - getWidth();
|
||||
|
||||
if (availableToScroll > 0) {
|
||||
scrollBy(Math.min(availableToScroll, deltaX), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (mTouchState == TOUCH_STATE_HORIZONTAL_SCROLLING) {
|
||||
final VelocityTracker velocityTracker = mVelocityTracker;
|
||||
velocityTracker.computeCurrentVelocity(VELOCITY_UNIT_PIXELS_PER_SECOND,
|
||||
mMaximumVelocity);
|
||||
int velocityX = (int) velocityTracker.getXVelocity();
|
||||
|
||||
if (velocityX > mDensityAdjustedSnapVelocity && mCurrentScreen > 0) {
|
||||
// Fling hard enough to move left
|
||||
snapToScreen(mCurrentScreen - 1);
|
||||
} else if (velocityX < -mDensityAdjustedSnapVelocity
|
||||
&& mCurrentScreen < getChildCount() - 1) {
|
||||
// Fling hard enough to move right
|
||||
snapToScreen(mCurrentScreen + 1);
|
||||
} else {
|
||||
snapToDestination();
|
||||
}
|
||||
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker.recycle();
|
||||
mVelocityTracker = null;
|
||||
}
|
||||
}
|
||||
|
||||
mTouchState = TOUCH_STATE_REST;
|
||||
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mTouchState = TOUCH_STATE_REST;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void computeScroll() {
|
||||
if (mScroller.computeScrollOffset()) {
|
||||
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
|
||||
postInvalidate();
|
||||
} else if (mNextScreen != INVALID_SCREEN) {
|
||||
mCurrentScreen = Math.max(0, Math.min(mNextScreen, getChildCount() - 1));
|
||||
|
||||
// Notify observer about screen change
|
||||
if (mOnScreenSwitchListener != null) {
|
||||
mOnScreenSwitchListener.onScreenSwitched(mCurrentScreen);
|
||||
}
|
||||
|
||||
mNextScreen = INVALID_SCREEN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the currently displayed screen.
|
||||
*
|
||||
* @return The index of the currently displayed screen.
|
||||
*/
|
||||
public int getCurrentScreen() {
|
||||
return mCurrentScreen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current screen.
|
||||
*
|
||||
* @param currentScreen The new screen.
|
||||
* @param animate True to smoothly scroll to the screen, false to snap instantly
|
||||
*/
|
||||
public void setCurrentScreen(final int currentScreen, final boolean animate) {
|
||||
mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount() - 1));
|
||||
if (animate) {
|
||||
snapToScreen(currentScreen, ANIMATION_SCREEN_SET_DURATION_MILLIS);
|
||||
} else {
|
||||
scrollTo(mCurrentScreen * getWidth(), 0);
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link OnScreenSwitchListener}.
|
||||
*
|
||||
* @param onScreenSwitchListener The listener for switch events.
|
||||
*/
|
||||
public void setOnScreenSwitchListener(final OnScreenSwitchListener onScreenSwitchListener) {
|
||||
mOnScreenSwitchListener = onScreenSwitchListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Snaps to the screen we think the user wants (the current screen for very small movements; the
|
||||
* next/prev screen for bigger movements).
|
||||
*/
|
||||
private void snapToDestination() {
|
||||
final int screenWidth = getWidth();
|
||||
int scrollX = getScrollX();
|
||||
int whichScreen = mCurrentScreen;
|
||||
int deltaX = scrollX - (screenWidth * mCurrentScreen);
|
||||
|
||||
// Check if they want to go to the prev. screen
|
||||
if ((deltaX < 0) && mCurrentScreen != 0
|
||||
&& ((screenWidth / FRACTION_OF_SCREEN_WIDTH_FOR_SWIPE) < -deltaX)) {
|
||||
whichScreen--;
|
||||
// Check if they want to go to the next screen
|
||||
} else if ((deltaX > 0) && (mCurrentScreen + 1 != getChildCount())
|
||||
&& ((screenWidth / FRACTION_OF_SCREEN_WIDTH_FOR_SWIPE) < deltaX)) {
|
||||
whichScreen++;
|
||||
}
|
||||
|
||||
snapToScreen(whichScreen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Snap to a specific screen, animating automatically for a duration proportional to the
|
||||
* distance left to scroll.
|
||||
*
|
||||
* @param whichScreen Screen to snap to
|
||||
*/
|
||||
private void snapToScreen(final int whichScreen) {
|
||||
snapToScreen(whichScreen, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Snaps to a specific screen, animating for a specific amount of time to get there.
|
||||
*
|
||||
* @param whichScreen Screen to snap to
|
||||
* @param duration -1 to automatically time it based on scroll distance; a positive number to
|
||||
* make the scroll take an exact duration.
|
||||
*/
|
||||
private void snapToScreen(final int whichScreen, final int duration) {
|
||||
/*
|
||||
* Modified by Yoni Samlan: Allow new snapping even during an ongoing scroll animation. This
|
||||
* is intended to make HorizontalPager work as expected when used in conjunction with a
|
||||
* RadioGroup used as "tabbed" controls. Also, make the animation take a percentage of our
|
||||
* normal animation time, depending how far they've already scrolled.
|
||||
*/
|
||||
mNextScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
|
||||
final int newX = mNextScreen * getWidth();
|
||||
final int delta = newX - getScrollX();
|
||||
|
||||
if (duration < 0) {
|
||||
// E.g. if they've scrolled 80% of the way, only animation for 20% of the duration
|
||||
mScroller.startScroll(getScrollX(), 0, delta, 0, (int) (Math.abs(delta)
|
||||
/ (float) getWidth() * ANIMATION_SCREEN_SET_DURATION_MILLIS));
|
||||
} else {
|
||||
mScroller.startScroll(getScrollX(), 0, delta, 0, duration);
|
||||
}
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for the event that the HorizontalPager switches to a new view.
|
||||
*/
|
||||
public static interface OnScreenSwitchListener {
|
||||
/**
|
||||
* Notifies listeners about the new screen. Runs after the animation completed.
|
||||
*
|
||||
* @param screen The new screen index.
|
||||
*/
|
||||
void onScreenSwitched(int screen);
|
||||
}
|
||||
}
|
||||
@ -4,9 +4,12 @@ import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.FrameLayout
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.commit
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.ray650128.gstreamer_demo_app.Constants
|
||||
import com.ray650128.gstreamer_demo_app.R
|
||||
@ -16,24 +19,23 @@ import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* MainActivity.kt
|
||||
* 應用程式主畫面
|
||||
*/
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
|
||||
private val viewModel: MainViewModel by viewModels()
|
||||
|
||||
private val splitViewModel: SplitViewModel by viewModels()
|
||||
|
||||
private val mContext: Context by lazy { this }
|
||||
|
||||
private var splitMode = 1
|
||||
private var oldSplitMode = 1
|
||||
|
||||
private lateinit var splitVideoViewAdapter: VideoViewAdapter
|
||||
|
||||
private var videos: List<List<Device>>? = null
|
||||
|
||||
private var currentPage = 0
|
||||
private var videoPageList: ArrayList<SplitViewFragment> = arrayListOf()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
@ -52,29 +54,8 @@ class MainActivity : AppCompatActivity() {
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
splitVideoViewAdapter.destroy()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun initContentView() = binding.apply {
|
||||
//region Content area
|
||||
splitVideoViewAdapter = VideoViewAdapter(supportFragmentManager, lifecycle)
|
||||
|
||||
viewPager.apply {
|
||||
adapter = splitVideoViewAdapter
|
||||
offscreenPageLimit = 100
|
||||
setPageTransformer(null)
|
||||
registerOnPageChangeCallback(object: ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
super.onPageSelected(position)
|
||||
currentPage = position
|
||||
splitViewModel.activePage.postValue(position)
|
||||
//Log.d("Split", "currentPage: $currentPage")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
button.setOnClickListener {
|
||||
if (splitMode == MainViewModel.PAGE_MODE_ONE) return@setOnClickListener
|
||||
viewModel.setSplitMode(MainViewModel.PAGE_MODE_ONE)
|
||||
@ -110,20 +91,22 @@ class MainActivity : AppCompatActivity() {
|
||||
viewModel.cameraList.observe(this) { list ->
|
||||
this.videos = list
|
||||
reloadVideoViews(this.videos)
|
||||
currentPage = 0
|
||||
}
|
||||
}
|
||||
|
||||
private fun reloadVideoViews(list: List<List<Device>>?) = MainScope().launch {
|
||||
binding.viewPager.setCurrentItem(0, false)
|
||||
for (i in 0 until splitVideoViewAdapter.itemCount) {
|
||||
splitVideoViewAdapter.pause()
|
||||
splitVideoViewAdapter.destroy()
|
||||
val oldListCount = videoPageList.size
|
||||
for (videoPage in videoPageList) {
|
||||
supportFragmentManager.commit {
|
||||
remove(videoPage)
|
||||
}
|
||||
}
|
||||
binding.viewPager.removeAllViews()
|
||||
videoPageList.clear()
|
||||
|
||||
if (oldListCount > 0) {
|
||||
delay(500L)
|
||||
}
|
||||
//delay(oldSplitMode * Constants.CONF_DELAY_BASE_MILLIS)
|
||||
delay((oldSplitMode * 100) + Constants.CONF_DELAY_BASE_MILLIS)
|
||||
oldSplitMode = splitMode
|
||||
splitVideoViewAdapter.clear()
|
||||
// 如果群組內沒有裝置,則顯示底圖
|
||||
if (list.isNullOrEmpty()) {
|
||||
binding.viewPager.setBackgroundResource(R.drawable.bg_not_in_playing)
|
||||
@ -135,10 +118,16 @@ class MainActivity : AppCompatActivity() {
|
||||
splitMode = splitMode,
|
||||
pageData = ArrayList(list[i])
|
||||
)
|
||||
splitVideoViewAdapter.add(i, splitFragment)
|
||||
videoPageList.add(i, splitFragment)
|
||||
|
||||
val frameLayout = FrameLayout(mContext).apply {
|
||||
id = View.generateViewId()
|
||||
}
|
||||
binding.viewPager.addView(frameLayout)
|
||||
supportFragmentManager.commit {
|
||||
add(frameLayout.id, splitFragment, "$i")
|
||||
}
|
||||
}
|
||||
currentPage = 0
|
||||
//binding.viewPager.currentItem = 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
5
app/src/main/res/color/color_monitor_icon.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="false" android:color="#9b9b9b" />
|
||||
<item android:state_enabled="true" android:color="#FF000000" />
|
||||
</selector>
|
||||
BIN
app/src/main/res/drawable-hdpi/ic_about.png
Normal file
|
After Width: | Height: | Size: 612 B |
BIN
app/src/main/res/drawable-hdpi/ic_message.png
Normal file
|
After Width: | Height: | Size: 455 B |
|
Before Width: | Height: | Size: 3.9 KiB |
BIN
app/src/main/res/drawable-mdpi/bg_main_screen.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
app/src/main/res/drawable-mdpi/bg_welcome_screen.png
Normal file
|
After Width: | Height: | Size: 117 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_about.png
Normal file
|
After Width: | Height: | Size: 438 B |
BIN
app/src/main/res/drawable-mdpi/ic_add_camera.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_back_arrow.png
Normal file
|
After Width: | Height: | Size: 330 B |
BIN
app/src/main/res/drawable-mdpi/ic_drawer_menu.png
Normal file
|
After Width: | Height: | Size: 321 B |
BIN
app/src/main/res/drawable-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_launcher_adaptive_fore.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_light_off.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_light_on.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_message.png
Normal file
|
After Width: | Height: | Size: 355 B |
BIN
app/src/main/res/drawable-mdpi/ic_modify_device.png
Normal file
|
After Width: | Height: | Size: 540 B |
BIN
app/src/main/res/drawable-mdpi/ic_scan_camera.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_split_four_views.png
Normal file
|
After Width: | Height: | Size: 421 B |
BIN
app/src/main/res/drawable-mdpi/ic_split_menu.png
Normal file
|
After Width: | Height: | Size: 334 B |
BIN
app/src/main/res/drawable-mdpi/ic_split_menu_line.png
Normal file
|
After Width: | Height: | Size: 541 B |
BIN
app/src/main/res/drawable-mdpi/ic_split_nine_views.png
Normal file
|
After Width: | Height: | Size: 529 B |
BIN
app/src/main/res/drawable-mdpi/ic_split_one_view.png
Normal file
|
After Width: | Height: | Size: 309 B |
BIN
app/src/main/res/drawable-mdpi/img_btn_scan.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
app/src/main/res/drawable-mdpi/img_logo.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/main/res/drawable-mdpi/loadingone.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
app/src/main/res/drawable-mdpi/loadingthree.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
app/src/main/res/drawable-mdpi/loadingtwo.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
app/src/main/res/drawable-xhdpi/bg_main_screen.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
app/src/main/res/drawable-xhdpi/bg_welcome_screen.png
Normal file
|
After Width: | Height: | Size: 295 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_about.png
Normal file
|
After Width: | Height: | Size: 790 B |
BIN
app/src/main/res/drawable-xhdpi/ic_add_camera.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_back_arrow.png
Normal file
|
After Width: | Height: | Size: 544 B |
BIN
app/src/main/res/drawable-xhdpi/ic_drawer_menu.png
Normal file
|
After Width: | Height: | Size: 468 B |
BIN
app/src/main/res/drawable-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_launcher_adaptive_fore.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_light_off.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_light_on.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_message.png
Normal file
|
After Width: | Height: | Size: 545 B |
BIN
app/src/main/res/drawable-xhdpi/ic_modify_device.png
Normal file
|
After Width: | Height: | Size: 906 B |
BIN
app/src/main/res/drawable-xhdpi/ic_scan_camera.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_split_four_views.png
Normal file
|
After Width: | Height: | Size: 616 B |
BIN
app/src/main/res/drawable-xhdpi/ic_split_menu.png
Normal file
|
After Width: | Height: | Size: 513 B |
BIN
app/src/main/res/drawable-xhdpi/ic_split_menu_line.png
Normal file
|
After Width: | Height: | Size: 736 B |
BIN
app/src/main/res/drawable-xhdpi/ic_split_nine_views.png
Normal file
|
After Width: | Height: | Size: 855 B |
BIN
app/src/main/res/drawable-xhdpi/ic_split_one_view.png
Normal file
|
After Width: | Height: | Size: 505 B |
BIN
app/src/main/res/drawable-xhdpi/img_btn_scan.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
app/src/main/res/drawable-xhdpi/img_logo.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
app/src/main/res/drawable-xhdpi/loadingone.png
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
app/src/main/res/drawable-xhdpi/loadingthree.png
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
app/src/main/res/drawable-xhdpi/loadingtwo.png
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
app/src/main/res/drawable-xxhdpi/bg_main_screen.png
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
app/src/main/res/drawable-xxhdpi/bg_welcome_screen.png
Normal file
|
After Width: | Height: | Size: 517 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_about.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_add_camera.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_back_arrow.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_drawer_menu.png
Normal file
|
After Width: | Height: | Size: 651 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_launcher_adaptive_fore.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_light_off.png
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_light_on.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_message.png
Normal file
|
After Width: | Height: | Size: 750 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_modify_device.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_scan_camera.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_split_four_views.png
Normal file
|
After Width: | Height: | Size: 891 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_split_menu.png
Normal file
|
After Width: | Height: | Size: 686 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_split_menu_line.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_split_nine_views.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_split_one_view.png
Normal file
|
After Width: | Height: | Size: 720 B |
BIN
app/src/main/res/drawable-xxhdpi/img_btn_scan.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
app/src/main/res/drawable-xxhdpi/img_logo.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
app/src/main/res/drawable-xxhdpi/loadingone.png
Normal file
|
After Width: | Height: | Size: 119 KiB |
BIN
app/src/main/res/drawable-xxhdpi/loadingthree.png
Normal file
|
After Width: | Height: | Size: 126 KiB |
BIN
app/src/main/res/drawable-xxhdpi/loadingtwo.png
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/bg_main_screen.png
Normal file
|
After Width: | Height: | Size: 140 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/bg_welcome_screen.png
Normal file
|
After Width: | Height: | Size: 755 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_about.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_add_camera.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_back_arrow.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_drawer_menu.png
Normal file
|
After Width: | Height: | Size: 884 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_launcher_adaptive_fore.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_light_off.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_light_on.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_message.png
Normal file
|
After Width: | Height: | Size: 968 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_modify_device.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_scan_camera.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_split_four_views.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_split_menu.png
Normal file
|
After Width: | Height: | Size: 864 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_split_menu_line.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_split_nine_views.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_split_one_view.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/img_btn_scan.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/img_logo.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/loadingone.png
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/loadingthree.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/loadingtwo.png
Normal file
|
After Width: | Height: | Size: 176 KiB |
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:topLeftRadius="18dp" android:topRightRadius="18dp" />
|
||||
<solid android:color="@android:color/white" />
|
||||
</shape>
|
||||
5
app/src/main/res/drawable/bg_calendar_available_date.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
|
||||
<size android:width="29dp" android:height="29dp" />
|
||||
<stroke android:width="2dp" android:color="@color/color_blue2" />
|
||||
</shape>
|
||||