/*
* Copyright 2015 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in 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 to in 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.
*/
package com.looklook.xinghongfei.looklook.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.ColorInt;
import android.support.annotation.FloatRange;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Property;
import com.looklook.xinghongfei.looklook.R;
import com.looklook.xinghongfei.looklook.util.AnimUtils;
import com.looklook.xinghongfei.looklook.util.ColorUtils;
/**
* An image view which supports parallax scrolling and applying a scrim onto it's content. Get it.
*
* It also has a custom pinned state, for use via state lists.
*/
public class ParallaxScrimageView extends FourThreeImageView {
private static final int[] STATE_PINNED = {R.attr.state_pinned};
private final Paint scrimPaint;
private int imageOffset;
private int minOffset;
private float scrimAlpha = 0f;
private float maxScrimAlpha = 1f;
private int scrimColor = 0x00000000;
private float parallaxFactor = -0.5f;
private boolean isPinned = false;
private boolean immediatePin = false;
public static final Property<ParallaxScrimageView, Float> OFFSET = new AnimUtils
.FloatProperty<ParallaxScrimageView>("offset") {
@Override
public void setValue(ParallaxScrimageView parallaxScrimageView, float value) {
parallaxScrimageView.setOffset(value);
}
@Override
public Float get(ParallaxScrimageView parallaxScrimageView) {
return parallaxScrimageView.getOffset();
}
};
public ParallaxScrimageView(Context context, AttributeSet attrs) {
super(context, attrs);
final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable
.ParallaxScrimageView);
if (a.hasValue(R.styleable.ParallaxScrimageView_scrimColor)) {
scrimColor = a.getColor(R.styleable.ParallaxScrimageView_scrimColor, scrimColor);
}
if (a.hasValue(R.styleable.ParallaxScrimageView_scrimAlpha)) {
scrimAlpha = a.getFloat(R.styleable.ParallaxScrimageView_scrimAlpha, scrimAlpha);
}
if (a.hasValue(R.styleable.ParallaxScrimageView_maxScrimAlpha)) {
maxScrimAlpha = a.getFloat(R.styleable.ParallaxScrimageView_maxScrimAlpha,
maxScrimAlpha);
}
if (a.hasValue(R.styleable.ParallaxScrimageView_parallaxFactor)) {
parallaxFactor = a.getFloat(R.styleable.ParallaxScrimageView_parallaxFactor,
parallaxFactor);
}
a.recycle();
scrimPaint = new Paint();
scrimPaint.setColor(ColorUtils.modifyAlpha(scrimColor, scrimAlpha));
}
public float getOffset() {
return getTranslationY();
}
public void setOffset(float offset) {
offset = Math.max(minOffset, offset);
if (offset != getTranslationY()) {
setTranslationY(offset);
imageOffset = (int) (offset * parallaxFactor);
setScrimAlpha(Math.min((-offset / getMinimumHeight()) * maxScrimAlpha, maxScrimAlpha));
ViewCompat.postInvalidateOnAnimation(this);
}
setPinned(offset == minOffset);
}
public void setScrimColor(@ColorInt int scrimColor) {
if (this.scrimColor != scrimColor) {
this.scrimColor = scrimColor;
ViewCompat.postInvalidateOnAnimation(this);
}
}
public void setScrimAlpha(@FloatRange(from = 0f, to = 1f) float alpha) {
if (scrimAlpha != alpha) {
scrimAlpha = alpha;
scrimPaint.setColor(ColorUtils.modifyAlpha(scrimColor, scrimAlpha));
ViewCompat.postInvalidateOnAnimation(this);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (h > getMinimumHeight()) {
minOffset = getMinimumHeight() - h;
}
}
@Override
protected void onDraw(Canvas canvas) {
if (imageOffset != 0) {
canvas.save();
canvas.translate(0f, imageOffset);
canvas.clipRect(0f, 0f, canvas.getWidth(), canvas.getHeight() + imageOffset);
super.onDraw(canvas);
canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), scrimPaint);
canvas.restore();
} else {
super.onDraw(canvas);
canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), scrimPaint);
}
}
@Override
public int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isPinned) {
mergeDrawableStates(drawableState, STATE_PINNED);
}
return drawableState;
}
public boolean isPinned() {
return isPinned;
}
public void setPinned(boolean isPinned) {
if (this.isPinned != isPinned) {
this.isPinned = isPinned;
refreshDrawableState();
if (isPinned && immediatePin) {
jumpDrawablesToCurrentState();
}
}
}
public boolean isImmediatePin() {
return immediatePin;
}
/**
* As the pinned state is designed to work with a {@see StateListAnimator}, we may want to short
* circuit this animation in certain situations e.g. when flinging a list.
*/
public void setImmediatePin(boolean immediatePin) {
this.immediatePin = immediatePin;
}
}