Scott effect

  • I did not read the source code, because I just want to try another way. Android imitation of AmAP can be stretched BottomSheet

The following is the effect I achieved with MotionLayout. If it is not silky and smooth, it is up to you to optimize

Demo. Apk Download experience

The reason

  • This was a great experience when I was using Amap, and then I thought, how can I achieve something similar
  • I’ve been looking at some MotionLayout stuff lately, so I just gave it a try

MotionLayout

  • Part I – IV: How to use MotionLayout
  • I won’t go into too much detail here, but I’ll conclude by creating it in the XML folderxxscene.xmlIt is mainly used to describe the key frame and view state change of scene animation
  • xxscene.xmlThe content includes three key contents:
  1. TransitionThe transition

ConstraintSetStart: Starts the constraint scenario

ConstraintSetEnd: ends the constraint scenario

App :dragDirection=”dragUp”

  1. KeyFrameSetKey frame set

The KeyAttribute key frames

App :framePosition, progress

App :target=”@id/ XXX Description of the view ID

  1. ConstraintSetConstraint set
 <Transition
        app:constraintSetEnd="@id/slideup_end"
        app:constraintSetStart="@id/slideup_start"
        app:duration="600"
        app:interpolator="easeIn">
        <OnSwipe
            app:dragDirection="dragUp"
            app:maxAcceleration="600"
            app:touchAnchorSide="top"
            app:touchAnchorId="@id/content"
           />
        <KeyFrameSet>
            <KeyAttribute
                android:alpha="0"
                app:framePosition="45"
                app:target="@id/sugar_title" />

            <KeyAttribute
                android:alpha="1"
                app:framePosition="90"
                app:target="@id/sugar_title" />
        ...
        </KeyFrameSet>
 </Transition>   
 
 <ConstraintSet android:id="@+id/slideup_start"<Constraint ·· /> </ConstraintSet>Copy the code

Disassembly process

  • Amap is pull-up followed by three sections, as shown in the figure

  • MotionLayoutHow can you achieve this three-step effect with only one initial constraint and one end constraint, and no intermediate constraint?
  • Answer: Using progress,MotionLayoutWith the progress
  • Progress is being made. When will the next operation be performed? When will the last operation be performed?
  • A: According to the gesture, we can judge whether the user will pull up or pull down next, set the threshold of the stage, over the next step, not over the previous step back
  • In AmAP, the gesture is effective only when the hand touches BottomView, so it is necessary to determine whether the touch event is within the view range

After dismantling

The implementation process

  • Set the threshold
/** * public final staticfloatPROGRESS_START = 0f; /** * top threshold */ public final staticfloatPROGRESS_TOP = 0.9 f; /** * public final staticfloatPROGRESS_BOTTOM = 0.1 f; /** * public final staticfloatPROGRESS_MIDDLE = 0.6 f; /** * public final staticfloatPROGRESS_END = 1.0 f;Copy the code
  • rewriteMotionLayouttheonTouchEventEvent, usinghasMiddleBoolean values determine whether there are intermediate states
 @Override
    public boolean onTouchEvent(MotionEvent event) {
        float progress = getProgress();
        View viewGroup = findViewById(R.id.content);
        Rect mRect = new Rect();
        if(! mTouchStared) { viewGroup.getHitRect(mRect); mTouchStared = mRect.contains((int) event.getX(), (int) event.getY()); }float endY;
        if (hasMiddle) {
            switch (event.getActionMasked()) {
                case MotionEvent.ACTION_CANCEL:
                    mTouchStared = false;
                    break;
                case MotionEvent.ACTION_DOWN:
                    startY = event.getY();
                    break;
                caseMotionEvent.ACTION_UP: endY = event.getY(); // Gesture downif ((endY - startY) > 0) {
                        if (progress >= PROGRESS_TOP) {
                            mTouchStared = false;
                            handleProgress(PROGRESS_END);

                        }
                        if (progress < PROGRESS_TOP && progress >= PROGRESS_MIDDLE) {
                            handleProgress(PROGRESS_MIDDLE);
                        }
                        if(progress < PROGRESS_MIDDLE) { handleProgress(PROGRESS_START); } // gesture up}else {
                        if (progress <= PROGRESS_BOTTOM) {
                            handleProgress(PROGRESS_START);
                        }
                        if (progress > PROGRESS_BOTTOM && progress <= PROGRESS_MIDDLE) {
                            handleProgress(PROGRESS_MIDDLE);
                        }
                        if (progress > PROGRESS_MIDDLE) {
                            mTouchStared = false; handleProgress(PROGRESS_END); }}returnmTouchStared; }}else {
            if (event.getActionMasked() == MotionEvent.ACTION_CANCEL || event.getActionMasked() == MotionEvent.ACTION_UP) {
                mTouchStared = false;
                returnsuper.onTouchEvent(event); }}return mTouchStared && super.onTouchEvent(event);

    }
Copy the code
  • bottom_scene.xml
  1. Pull-up exceeds the top thresholdPROGRESS_TOPAfter the title appears in the screen, the rest of the time appears outside the screen can be;
  2. The initial state right herescaleXandscaleYI’m going to set it to 0.9 and I’m going to set it to 1, just for the sake of transition, so you don’t have to change it
  3. Background color transition, start with transparency, end with white background. Intermediate key frame 95 becomes pure white background

Results and improvements

  • Setting allows for intermediate states after the next step in the process, as shown, is too blunt

  • To improve the direction
  1. Animation should be constant, howeversetProgress(pro);But one step straight;
  2. Set time interval uniform speed to reach the final progress, the source has been annotated in detail. See the top rendering after improvement;
 private void handleProgress(floatProgress) {// If the progress to be set is the same as the current progress, no action is takenif (progress == getProgress()){
            return; } // Long time = 200; // Progress interval >0 indicates pull-up. < 0 indicates slidefloat interval = progress - getProgress();
        long startTime, endTime;
        if (interval > 0) {
            startTime = (long) (getProgress() * time);
            endTime = (long) (progress * time);
        } else {
            endTime = (long) (getProgress() * time);
            startTime = (long) (progress * time);
        }
        if(timeDisposable ! = null){ timeDisposable.dispose(); } //startTime Indicates the initial time. Endtime-starttime indicates the number of times. 0 indicates the delay time Observable.intervalRange(startTime, endTime - startTime, 0, 3, TimeUnit.MILLISECONDS) .observeOn(Schedulers.io()) .compose(((BaseActivity) getContext()).getProvider().bindToLifecycle()) .observeOn(AndroidSchedulers.mainThread()) .map(new Function<Long, Long>() {@override public Long apply(Long aLong) throws Exception {// Slide requires reverseif (interval < 0) {
                            long interStart = aLong - startTime;
                            return endTime - interStart;
                        }
                        return aLong;
                    }
                })
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        float pro = (Float.valueOf(aLong) / time);
                        setProgress(pro); }}); }Copy the code

The source code has been put into the Sugar demo, sugar is a library I will maintain for a long time ⬇️⬇️⬇️

🍯 Sugar easy and fast development of Android projects, a collection of popular framework packages

About me

  • Email: [email protected]
  • The Denver nuggets: juejin. Cn/user / 287597…
  • Jane: www.jianshu.com/u/114bbbfb9…
  • apkbus: www.apkbus.com/?496060
  • github: github.com/wobiancao

License

Copyright 2019, wobiancao       
  
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except inThe compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed toin writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
   
Copy the code