@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (getChildCount() != 2) { throw new IllegalStateException("DraggedPanelLayout must have 2 children!"); } bottomPanel = getChildAt(0); bottomPanel.layout(left, top, right, bottom - bottomPanelPeekHeight); slidingPanel = getChildAt(1); if (!opened) { int panelMeasuredHeight = slidingPanel.getMeasuredHeight(); slidingPanel.layout(left, bottom - bottomPanelPeekHeight, right, bottom - bottomPanelPeekHeight + panelMeasuredHeight); } }
<com.dataart.animtest.DraggedPanelLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:dp="http://schemas.android.com/apk/res/com.dataart.animtest" android:layout_width="match_parent" android:layout_height="match_parent" dp:bottom_panel_height="64dp" tools:context=".MainActivity" > <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/stripes" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:contentDescription="@string/android" android:src="@drawable/android" /> </FrameLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF" android:text="@string/hello_world" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="@string/random_button" /> </FrameLayout> </com.dataart.animtest.DraggedPanelLayout>
@Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { startDragging(event); } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (touching) { float translation = event.getY() - touchY; translation = boundTranslation(translation); slidingPanel.setTranslationY(translation); bottomPanel .setTranslationY((float) (opened ? -(getMeasuredHeight() - bottomPanelPeekHeight - translation) * parallaxFactor : translation * parallaxFactor)); } } else if (event.getAction() == MotionEvent.ACTION_UP) { isBeingDragged = false; touching = false; } return true; }
Here I want to make a small digression and talk about layout and translation. Layout is the process of arranging your markup, i.e., for each View, its size and position on the screen is determined recursively. As it is not difficult to guess, this is a costly operation. That is why it is not recommended to perform this procedure during animation, if you just do not want to get the effect of braking animation. The translation property, in turn, allows you to set a cheap displacement of an element relative to a given position without performing the layout of the entire hierarchy. This is very useful for animations. In addition to translation, the View has properties such as Rotation, Scale. It is also possible to do more advanced transformations by creating a subclass of the desired component and performing the necessary transformations of the canvas. An example of this can be seen in my previous article about animating a ListView.
public void finishAnimateToFinalPosition(float velocityY) { final boolean flinging = Math.abs(velocityY) > 0.5; boolean opening; float distY; long duration; if (flinging) { opening = velocityY < 0; distY = calculateDistance(opening); duration = Math.abs(Math.round(distY / velocityY)); animatePanel(opening, distY, duration); } else { boolean halfway = Math.abs(slidingPanel.getTranslationY()) >= (getMeasuredHeight() - bottomPanelPeekHeight) / 2; opening = opened ? !halfway : halfway; distY = calculateDistance(opening); duration = Math.round(300 * (double) Math.abs((double) slidingPanel.getTranslationY()) / (double) (getMeasuredHeight() - bottomPanelPeekHeight)); } animatePanel(opening, distY, duration); }
public void animatePanel(final boolean opening, float distY, long duration) { ObjectAnimator slidingPanelAnimator = ObjectAnimator.ofFloat(slidingPanel, View.TRANSLATION_Y, slidingPanel.getTranslationY(), slidingPanel.getTranslationY() + distY); ObjectAnimator bottomPanelAnimator = ObjectAnimator.ofFloat(bottomPanel, View.TRANSLATION_Y, bottomPanel.getTranslationY(), bottomPanel.getTranslationY() + (float) (distY * parallaxFactor)); AnimatorSet set = new AnimatorSet(); set.playTogether(slidingPanelAnimator, bottomPanelAnimator); set.setDuration(duration); set.setInterpolator(sDecelerator); set.addListener(new MyAnimListener(opening)); set.start(); }
@Override public void onAnimationEnd(Animator animation) { setOpenedState(opening); bottomPanel.setTranslationY(0); slidingPanel.setTranslationY(0); requestLayout(); }
@Override public boolean onInterceptTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { touchY = event.getY(); } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (Math.abs(touchY - event.getY()) > touchSlop) { isBeingDragged = true; startDragging(event); } } else if (event.getAction() == MotionEvent.ACTION_UP) { isBeingDragged = false; } return isBeingDragged; }
Source: https://habr.com/ru/post/191586/
All Articles