/*
* Created by LuaView.
* Copyright (c) 2017, Alibaba Group. All rights reserved.
*
* This source code is licensed under the MIT.
* For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
*/
package com.taobao.luaview.view.foreground;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import com.taobao.android.luaview.R;
/**
* Delegate that actually does the foreground things, so that the logic can be shared between views
* and so that others can easily create views that support a foreground
*/
public class ForegroundDelegate {
private Drawable mForeground;
private final Rect mSelfBounds = new Rect();
private final Rect mOverlayBounds = new Rect();
private int mForegroundGravity = Gravity.FILL;
protected boolean mForegroundInPadding = true;
boolean mForegroundBoundsChanged = false;
public ForegroundDelegate() {
}
public static void setupDefaultForeground(View view) {
setupDefaultForeground(view, null, null);
}
public static void setupDefaultForeground(View view, Integer color, Integer alpha) {
if (view instanceof IForeground && ((IForeground) view).hasForeground() == false && view.getResources() != null) {
setupForeground(view, view.getResources().getDrawable(R.drawable.lv_click_foreground), color, alpha);
}
}
private static void setupForeground(View view, Drawable drawable, Integer color, Integer alpha) {
if (view instanceof IForeground) {
if (color != null) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
if (drawable instanceof RippleDrawable) {
RippleDrawable rippleDrawable = (RippleDrawable) drawable;
rippleDrawable.setColor(ColorStateList.valueOf(color));
if (alpha != null) {
rippleDrawable.setAlpha(alpha);
}
}
}
}
((IForeground) view).setForeground(drawable);
}
}
public static void clearForeground(View view) {
if (view instanceof IForeground) {
((IForeground) view).clearForeground();
}
}
public void init(Context context) {
}
public void init(Context context, AttributeSet attrs, int defStyle, int defStyleRes) {
}
public void onLayout(boolean changed, int left, int top, int right, int bottom) {
mForegroundBoundsChanged = true;
// mForegroundBoundsChanged = changed;
}
public void onSizeChanged(int w, int h, int oldw, int oldh) {
mForegroundBoundsChanged = true;
}
/**
* Returns the drawable used as the foreground of this FrameLayout. The
* foreground drawable, if non-null, is always drawn on top of the children.
*
* @return A Drawable or null if no foreground was set.
*/
public Drawable getForeground() {
return mForeground;
}
/**
* Supply a Drawable that is to be rendered on top of all of the child
* views in the frame layout. Any padding in the Drawable will be taken
* into account by ensuring that the children are inset to be placed
* inside of the padding area.
*
* @param drawable The Drawable to be drawn on top of the children.
*/
public void setForeground(View view, Drawable drawable) {
if (view != null) {
if (mForeground != drawable) {
if (mForeground != null) {
mForeground.setCallback(null);
view.unscheduleDrawable(mForeground);
}
mForeground = drawable;
if (drawable != null) {
view.setWillNotDraw(false);
drawable.setCallback(view);
if (drawable.isStateful()) {
drawable.setState(view.getDrawableState());
}
if (mForegroundGravity == Gravity.FILL) {
Rect padding = new Rect();
drawable.getPadding(padding);
}
//update bounds
updateBounds(view, drawable);//added by song
} else {
view.setWillNotDraw(true);
}
view.requestLayout();
view.invalidate();
}
}
}
public int getForegroundGravity() {
return mForegroundGravity;
}
public void setForegroundGravity(View view, int foregroundGravity) {
if (view != null) {
if (mForegroundGravity != foregroundGravity) {
if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
foregroundGravity |= Gravity.START;
}
if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
foregroundGravity |= Gravity.TOP;
}
mForegroundGravity = foregroundGravity;
if (mForegroundGravity == Gravity.FILL && mForeground != null) {
Rect padding = new Rect();
mForeground.getPadding(padding);
}
view.requestLayout();
}
}
}
public void jumpDrawablesToCurrentState() {
if (mForeground != null) mForeground.jumpToCurrentState();
}
public void drawableStateChanged(View view) {
if (view != null) {
if (mForeground != null && mForeground.isStateful()) {
mForeground.setState(view.getDrawableState());
}
}
}
public void draw(View view, Canvas canvas) {
if (view != null) {
if (mForeground != null) {
final Drawable foreground = mForeground;
if (mForegroundBoundsChanged) {
mForegroundBoundsChanged = false;
updateBounds(view, foreground);
}
foreground.draw(canvas);
}
}
}
public void updateBounds(View view) {
updateBounds(view, mForeground);
}
/**
* 更新bounds
*
* @param view
* @param drawable
*/
private void updateBounds(View view, Drawable drawable) {
if (drawable != null) {
final Rect selfBounds = mSelfBounds;
final Rect overlayBounds = mOverlayBounds;
final int w = view.getRight() - view.getLeft();
final int h = view.getBottom() - view.getTop();
if (mForegroundInPadding) {
selfBounds.set(0, 0, w, h);
} else {
selfBounds.set(view.getPaddingLeft(), view.getPaddingTop(), w - view.getPaddingRight(), h - view.getPaddingBottom());
}
Gravity.apply(mForegroundGravity, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), selfBounds, overlayBounds);
drawable.setBounds(overlayBounds);
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void drawableHotspotChanged(float x, float y) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (mForeground != null) {
mForeground.setHotspot(x, y);
}
}
}
}