package fr.neamar.kiss.ui; import android.content.Context; import android.graphics.Canvas; import android.os.Build; import android.util.AttributeSet; import android.view.View; import android.widget.EdgeEffect; /** * View that renders that over-scroll/"pulled too far" effect * * Parts (or even all) of the given effect parameters may be discarded with the underlying Android * platform does not support them. */ public class BottomPullEffectView extends View { private EdgeEffect effect; private float lastPullDistance; private float lastPullDisplacement; private boolean lastPullAnimated; private void init() {} public BottomPullEffectView(Context context) { super(context); this.init(); } public BottomPullEffectView(Context context, AttributeSet attrs) { super(context, attrs); this.init(); } public BottomPullEffectView(Context context, AttributeSet attrs, int flags) { super(context, attrs, flags); this.init(); } /** * Force the pull effect to display the given pull distance and left/right displacement * * @param distance Pull distance (0.0f – 1.0f) * @param displacement Left/right displacement (0.0f → right, 0.5f → center, 1.0f → left) * @param animated Should this pull eventually fade away? */ public void setPull(float distance, float displacement, boolean animated) { // Reset internal effect state by creating a new instance //XXX: This may cause unnecessary GC runs! this.effect = new EdgeEffect(this.getContext()); // Provide new pull effect data this.effect.setSize(this.getWidth(), this.getHeight()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { this.effect.onPull(distance, displacement); } else { this.effect.onPull(distance); } if(!animated) { // Prevent more than one frame being drawn this.effect.finish(); } this.lastPullDistance = distance; this.lastPullDisplacement = displacement; this.lastPullAnimated = animated; // Request scene to be redrawn this.invalidate(); } /** * Draw a release animation for the previous pull effect */ public void releasePull() { if(this.effect == null) { return; } // Recreate effect without `finish()`-ing it, so that the release effect will be // properly drawn if(!this.lastPullAnimated) { this.setPull(this.lastPullDistance, this.lastPullDisplacement, true); } this.effect.onRelease(); this.invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if(this.effect == null) { return; } final int canvas_save_count = canvas.save(); canvas.translate(-this.getWidth(), this.getHeight()); canvas.rotate(180, this.getWidth(), 0); this.effect.setSize(this.getWidth(), this.getHeight()); boolean invalidate = this.effect.draw(canvas); canvas.restoreToCount(canvas_save_count); if(invalidate) { this.invalidate(); } } }