Introduction to the
It’s common to use a sideside Activity to return, such as wechat. So how does it work. This article takes you through the implementation principle. I found an open source star with 2.6K on Github, and we analyzed how he implemented it
/ / star 2.6 k 'com. R0adkll: slidableactivity: at 2.0.5'Copy the code
Example of Slidr
It is very simple to use, first to set the transparent window background
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<! -- Customize your theme here. -->
<item name="android:textAllCaps">false</item>
<item name="android:windowActionBar">false</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
Copy the code
then
/ / setContent (View View) after Slidr. Attach (this);Copy the code
Here’s how it works in three steps
Step 1 Repackage the interface
Slidr.class
public static SlidrInterface attach(final Activity activity, final int statusBarColor1, final int statusBarColor2){
//0 create a sliding nested interface SliderPanel
final SliderPanel panel = initSliderPanel(activity, null);
//7 Set the panel slide listener for when it becomes closed or opened
// Listen for callbacks
panel.setOnPanelSlideListener(new SliderPanel.OnPanelSlideListener() {
...
Open/close, etc
});
// Return the lock interface
return initInterface(panel);
}
private static SliderPanel initSliderPanel(final Activity activity, final SlidrConfig config) {
Decorview / / 3
ViewGroup decorView = (ViewGroup)activity.getWindow().getDecorView();
//4 Get the content of our layout and delete it
View oldScreen = decorView.getChildAt(0);
decorView.removeViewAt(0);
//5 Setup the slider panel and attach it to the decor
// Create a SliderPanel and add it to the DecorView
SliderPanel panel = new SliderPanel(activity, oldScreen, config);
panel.setId(R.id.slidable_panel);
oldScreen.setId(R.id.slidable_content);
//6 Add our interface layout to the SliderPanel and add the SliderPanel to the decorView
panel.addView(oldScreen);
decorView.addView(panel, 0);
return panel;
}
Copy the code
Step 2 UseViewDragHelper.class
Dealing with sliding gestures
SliderPanel.class
private void init(a){.../ / 1 ViewDragHelper created
mDragHelper = ViewDragHelper.create(this, mConfig.getSensitivity(), callback);
mDragHelper.setMinVelocity(minVel);
mDragHelper.setEdgeTrackingEnabled(mEdgePosition);
//2 Setup the Dimmer View
mDimView = new View(getContext());
mDimView.setBackgroundColor(mConfig.getScrimColor());
mDimView.setAlpha(mConfig.getScrimStartAlpha());
addView(mDimView);
}
Copy the code
Step 3 handles the drag of our interface in viewDragHelper.callback
Let’s make it clear that the ViewDragHelper only handles the relationship between ParentView and its child views, and does not traverse all the way to the top View. This is how capture for the ViewDragHelper is implemented
@Nullable
public View findTopChildUnder(int x, int y) {
final int childCount = mParentView.getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
final View child = mParentView.getChildAt(mCallback.getOrderedChildIndex(i));
if (x >= child.getLeft() && x < child.getRight()
&& y >= child.getTop() && y < child.getBottom()) {
returnchild; }}return null;
}
Copy the code
The focus is on the implementation of the ViewDragHelper.callback Callback in sliderPanel.class, The author implements many directions of sliding processing mLeftCallback, mRightCallback, mTopCallback, mBottomCallback, mVerticalCallback, mHorizontalCallback. Let’s take mLeftCallback for analysis
private ViewDragHelper.Callback mLeftCallback = new ViewDragHelper.Callback() {
/ / to capture the View
@Override
public boolean tryCaptureView(View child, int pointerId) {
booleanedgeCase = ! mConfig.isEdgeOnly() || mDragHelper.isEdgeTouched(mEdgePosition, pointerId);// As mentioned earlier, our content is the top layer of the subview, mDecorView in this case refers to our contentView
return child.getId() == mDecorView.getId() && edgeCase;
}
// Drag, and finally move through view.offsetLeftAndRight(offset)
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return clamp(left, 0, mScreenWidth);
}
// Slide range
@Override
public int getViewHorizontalDragRange(View child) {
return mScreenWidth;
}
// Release processing to determine whether to roll back to the screen
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int left = releasedChild.getLeft();
int settleLeft = 0;
int leftThreshold = (int) (getWidth() * mConfig.getDistanceThreshold());
boolean isVerticalSwiping = Math.abs(yvel) > mConfig.getVelocityThreshold();
if(xvel > 0) {if(Math.abs(xvel) > mConfig.getVelocityThreshold() && ! isVerticalSwiping){ settleLeft = mScreenWidth; }else if(left > leftThreshold){ settleLeft = mScreenWidth; }}else if(xvel == 0) {if(left > leftThreshold){ settleLeft = mScreenWidth; }}// Scroll to left=0(normal layout) or left=mScreenWidth (scroll out of screen) to close the Activity
mDragHelper.settleCapturedViewAt(settleLeft, releasedChild.getTop());
invalidate();
}
// Convert the position percentage to determine the transparency of the indicator layer
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
float percent = 1f - ((float)left / (float)mScreenWidth);
if(mListener ! =null) mListener.onSlideChange(percent);
// Update the dimmer alpha
applyScrim(percent);
}
// Callback to Slidr to handle the Activity state
@Override
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
if(mListener ! =null) mListener.onStateChanged(state);
switch (state){
case ViewDragHelper.STATE_IDLE:
if(mDecorView.getLeft() == 0) {// State Open
if(mListener ! =null) mListener.onOpened();
}else{
// State Closed here callback to Slidr processing activity. Finish ()
if(mListener ! =null) mListener.onClosed();
}
break;
case ViewDragHelper.STATE_DRAGGING:
break;
case ViewDragHelper.STATE_SETTLING:
break; }}};Copy the code
For mDragHelper. SettleCapturedViewAt (settleLeft, releasedChild getTop ()); Inside, scroller.class is used to aid rolling, so override View.computeScroll() in SliderPanel.
@Override
public void computeScroll(a) {
super.computeScroll();
if(mDragHelper.continueSettling(true)){
ViewCompat.postInvalidateOnAnimation(this); }}Copy the code
conclusion
The overall scheme is shown in the following figure
In general, the principle is not complicated, just dragging the View through the ViewDragHelper.