English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Einleitung
Beim Erstellen eines Projekts war es notwendig, ein ScrollView-Effekt ähnlich dem der persönlichen Homepage von Weibo zu implementieren, bei dem das obere Bild vergrößert wird, wenn man nach unten zieht, bis zum oberen Rand. Daraufhin fand ich im Internet einen entsprechenden Implementierung, der sehr gut aussieht und einfach zu verstehen ist. (Link: Selbstdefinierte ScrollView zum Vergrößern des oberen Bildes beim Ziehen nach unten), daher habe ich hier nur ein wenig daran geändert, z.B. das Zentrieren des Bildes im Code, die dynamische Einstellung des zu vergrößernden Widgets, die Verwendung eines benutzerdefinierten maximalen Vergrößerungsfaktors usw., das sind alle sehr einfache Änderungen, und ich habe auch das Scrollen hinzugefügt (Projektbedarf).
Das Ergebnis ist wie folgt:
Idee
Wie immer, lassen wir uns zunächst die Idee sagen, die Idee ist wichtiger als der Code. Die spezifischen Schritte sind wie folgt:
1. Erhalte das zu vergrößernde Widget und seine Breite und Höhe;
2. Wenn der Widget oben ist, ziehe weiter nach unten, ändere die Breite und Höhe des Widgets durch LayoutParams;
3. Initialisiere die Parameter, wenn der Finger aufhebt, und springe den Widget zurück durch Property Animation.
Umsetzung
Direkt zum Code schauen
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); } // Verwendet, um den Position des Scrollens zu speichern private float y = 0f; // Die ursprüngliche Breite und Höhe von zoomView private int zoomViewWidth = 0; private int zoomViewHeight = 0; // ob gerade vergrößert wird private boolean mScaling = false; // vergrößerter View, Standard ist der erste Unter-View private View zoomView; public void setZoomView(View zoomView) { this.zoomView = zoomView; } // Gleitvergrößerungsfaktor, desto größer der Faktor, desto größer die Vergrößerung während des Gleitens private float mScaleRatio = 0.4f; public void setmScaleRatio(float mScaleRatio) { this.mScaleRatio = mScaleRatio; } // größte Vergrößerungsgröße private float mScaleTimes = 2f; public void setmScaleTimes(int mScaleTimes) { this.mScaleTimes = mScaleTimes; } // Rückprallzeitfaktor, desto kleiner der Faktor, desto schneller der Rückprall private float mReplyRatio = 0.5f; public void setmReplyRatio(float mReplyRatio) { this.mReplyRatio = mReplyRatio; } @Override protected void onFinishInflate() { super.onFinishInflate(); // keine Über-Scrolling, andernfalls könnte nach dem Hochscrollen ein Teil des Bereichs leer sein setOverScrollMode(OVER_SCROLL_NEVER); // erhalten Sie den Standard-ersten 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();//wenn zum oberen Rand gescrollt wird, wird der Standort aufgezeichnet } else { break; } } int distance = (int) ((ev.getY() - y)*mScaleRatio); if (distance < 0) break;//wenn nach unten gescrollt wird mScaling = true; setZoom(distance); return true; case MotionEvent.ACTION_UP: mScaling = false; replyView(); break; } return super.onTouchEvent(ev); } /**Vergrößern Sie das View*/ private void setZoom(float s) { float scaleTimes = (float) ((zoomViewWidth+s)/(zoomViewWidth*1.0)); // wenn die maximale Vergrößerung überschritten wird, wird direkt zurückgegangen if (scaleTimes > mScaleTimes) return; ViewGroup.LayoutParams layoutParams = zoomView.getLayoutParams(); layoutParams.width = (int) (zoomViewWidth + s); layoutParams.height = (int)(zoomViewHeight*((zoomViewWidth+s)/); // steuerelement horizontal zentriert ((MarginLayoutParams) layoutParams).setMargins(-(layoutParams.width) - zoomViewWidth) / 2, 0, 0, 0); zoomView.setLayoutParams(layoutParams); } /**Rückprall*/ private void replyView() { final float distance = zoomView.getMeasuredWidth() - zoomViewWidth; // Setze 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-Abhörer*/ public interface OnScrollListener{ void onScroll(int scrollX, int scrollY, int oldScrollX, int oldScrollY); } }
可以看到,在onTouchEvent方法中,先判断当前是否为放大状态,如果不是的话,就在顶部时记录触摸事件的位置,当然这个也可以写在ACTION_DOWN事件中,如果不在顶部,则不处理。
之后计算滑动的距离,如果是向下滑动,则不处理。需要注意的是这个距离是指当前位置与最开始的ACTION_DOWN动作的距离,因此当这个距离小于0时,便是‘未放大且向下滑’。这个时候应该滑动的是ScrollView,嗯,没问题。当距离不小于0时,开始放大控件,可以看到调用了setZoom方法。注意,在这里实际上控件的下拉放大、上拉恢复都做了,回弹其实也是调用这个方法。
抬手时回弹,这个就不需要多说了。
代码整体来说比较简单,如果你需要其他实现,也可以很方便地添加,比如我们要放大图片时像微博一样,旋转外部的菊花,放手时刷新数据怎么办?你完全可以在
在onTouchEvent中增加回调接口,然后在外部实现具体逻辑即可。
使用
可以直接像普通的ScollView一样使用,这个就不详细说明了。
源码:下载地址
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。
声明:本文内容来源于互联网,版权归原作者所有。内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:notice#oldtoolbag.com(在发邮件时,请将#更换为@进行举报,并提供相关证据。一经查实,本站将立即删除涉嫌侵权内容。)