English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Introduction
When I was working on a project before, I needed to implement a ScrollView effect similar to the Weibo personal homepage, where the top image is zoomed when you continue to pull down at the top. Then I found a related implementation on the Internet, which has a very good effect and the code is concise and easy to understand. (Link: Custom scrollView to implement top image zoom when pulling down at the top), so here I just made a few modifications based on it, such as controlling the image to be centered in the code, adding dynamic setting of the zoomed control widget, using a custom maximum zoom factor, etc., which are all simple modifications, and also added a sliding listener callback (required for the project).
The effect is as follows:
Idea
As usual, let's talk about the idea first, because the idea is the most important. The specific steps are as follows:
1. Obtain the control widget to be zoomed and get its width and height;
2. Continue to pull down at the top, and change the width and height of the widget through LayoutParams;
3. Initialize various parameters when the finger is lifted, and use property animation to rebound the control widget.
Implementation
Directly look at the code
public class HeadZoomScrollView extends ScrollView { public HeadZoomScrollView(Context context) { super(context); } public HeadZoomScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public HeadZoomScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } // Used to record the scroll position private float y = 0f; // The original width and height of zoomView private int zoomViewWidth = 0; private int zoomViewHeight = 0; // Whether the view is currently being magnified private boolean mScaling = false; // The view to be magnified, defaulting to the first child view private View zoomView; public void setZoomView(View zoomView) { this.zoomView = zoomView; } // Sliding magnification coefficient, the larger the coefficient, the greater the magnification during sliding private float mScaleRatio = 0.4f; public void setmScaleRatio(float mScaleRatio) { this.mScaleRatio = mScaleRatio; } // The maximum magnification factor private float mScaleTimes = 2f; public void setmScaleTimes(int mScaleTimes) { this.mScaleTimes = mScaleTimes; } // Rebound time coefficient, the smaller the coefficient, the faster the rebound private float mReplyRatio = 0.5f; public void setmReplyRatio(float mReplyRatio) { this.mReplyRatio = mReplyRatio; } @Override protected void onFinishInflate() { super.onFinishInflate(); // Prevent excessive scrolling, otherwise there will be some blank areas after scrolling up and down setOverScrollMode(OVER_SCROLL_NEVER); // Obtain the default first view if (getChildAt(0) != null && getChildAt(0) instanceof ViewGroup && zoomView == null) { ViewGroup vg = (ViewGroup) getChildAt(0); if (vg.getChildCount() > 0) { zoomView = vg.getChildAt(0); } } } @Override public boolean onTouchEvent(MotionEvent ev) { if (zoomViewWidth <= 0 || zoomViewHeight <= 0) { zoomViewWidth = zoomView.getMeasuredWidth(); zoomViewHeight = zoomView.getMeasuredHeight(); } if (zoomView == null || zoomViewWidth <= 0 || zoomViewHeight <= 0) { return super.onTouchEvent(ev); } switch (ev.getAction()) { case MotionEvent.ACTION_MOVE: if (!mScaling) { if (getScrollY() == 0) { y = ev.getY();//Record position when sliding to the top } break; } } int distance = (int) ((ev.getY() - y)*mScaleRatio); if (distance < 0) break;//If sliding down mScaling = true; setZoom(distance); return true; case MotionEvent.ACTION_UP: mScaling = false; replyView(); break; } return super.onTouchEvent(ev); } /**Zoom view*/ private void setZoom(float s) { float scaleTimes = (float) ((zoomViewWidth+s)/(zoomViewWidth*1.0)); // If it exceeds the maximum zoom factor, return directly if (scaleTimes > mScaleTimes) return; ViewGroup.LayoutParams layoutParams = zoomView.getLayoutParams(); layoutParams.width = (int) (zoomViewWidth + s); layoutParams.height = (int)(zoomViewHeight*((zoomViewWidth+s)/); // set control horizontal center ((MarginLayoutParams) layoutParams).setMargins(-(layoutParams.width) - zoomViewWidth) / 2, 0, 0, 0); zoomView.setLayoutParams(layoutParams); } /**Rebound*/ private void replyView() { final float distance = zoomView.getMeasuredWidth() - zoomViewWidth; // Set Animation ValueAnimator anim = ObjectAnimator.ofFloat(distance, 0.0F).setDuration((long) (distance * mReplyRatio)); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { setZoom((Float) animation.getAnimatedValue()); } }); anim.start(); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (onScrollListener != null) onScrollListener.onScroll(l, t, oldl, oldt); } private OnScrollListener onScrollListener; public void setOnScrollListener(OnScrollListener onScrollListener) { this.onScrollListener = onScrollListener; } /**Scrolling Listener*/ public interface OnScrollListener{ void onScroll(int scrollX, int scrollY, int oldScrollX, int oldScrollY); } }
You can see that in the onTouchEvent method, first judge whether the current state is zoomed in. If not, record the position of the touch event at the top. Of course, it is also possible to write it in the ACTION_DOWN event, and do not process if it is not at the top.
After that, calculate the sliding distance. If it is sliding down, do not process it. It should be noted that this distance refers to the distance between the current position and the ACTION_DOWN action at the beginning, so when this distance is less than 0, it is 'not zoomed in && sliding down'. At this time, the ScrollView should be scrolled. Well, no problem. When the distance is not less than 0, start to zoom in on the control. You can see that the setZoom method is called. Note that in fact, the control's pull-down zooming, pull-up recovery, and rebound are all done here. Rebound actually also calls this method.
Rebound when lifting your hand, which does not need to be said.
The code is relatively simple overall. If you need other implementations, it can also be easily added, for example, when we need to zoom in on an image like Weibo, how to refresh the data when we release our hands? You can completely do this in
Add a callback interface in onTouchEvent, and then implement the specific logic externally.
Usage
You can use it directly like a normal ScollView, so there is no need to elaborate on this.
Source Code:Download Address
That's all for this article. I hope it will be helpful to everyone's learning, and I also hope everyone will support the Yelling Tutorial more.
Declaration: The content of this article is from the Internet, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, does not edit the content manually, and does not assume any relevant legal liability. If you find any content suspected of copyright infringement, please send an email to notice#w3Please send an email to codebox.com (replace # with @ when sending an email) to report any infringement, and provide relevant evidence. Once verified, this site will immediately delete the suspected infringing content.