/* * Copyright (C) 2014 Andrey Kulikov (andkulikov@gmail.com) * * 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.transitionseverywhere.utils; import android.animation.LayoutTransition; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.os.Build; import android.util.AttributeSet; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import com.transitionseverywhere.R; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; /** * Created by Andrey Kulikov on 15.11.14. */ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) class ViewOverlayPreJellybean extends FrameLayout { private static final Field FIELD_VIEW_PARENT = ReflectionUtils.getPrivateField(View.class, "mParent"); private List<Drawable> mDrawableOverlays; public ViewOverlayPreJellybean(Context context) { super(context); init(); } public ViewOverlayPreJellybean(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ViewOverlayPreJellybean(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mDrawableOverlays = new ArrayList<Drawable>(); } @Override public void addView(View child, int left, int top) { if (child.getParent() instanceof ViewGroup) { ViewGroup parent = (ViewGroup) child.getParent(); LayoutTransition layoutTransition = null; if (parent.getLayoutTransition() != null) { layoutTransition = parent.getLayoutTransition(); parent.setLayoutTransition(null); } parent.removeView(child); if (layoutTransition != null) { parent.setLayoutTransition(layoutTransition); } if (child.getParent() != null) { // LayoutTransition will cause the child to delay removal - cancel it ViewGroupUtils.cancelLayoutTransition(parent); // fail-safe if view is still attached for any reason if (child.getParent() != null && FIELD_VIEW_PARENT != null) { ReflectionUtils.setFieldValue(child, FIELD_VIEW_PARENT, null); } } if (child.getParent() != null) { return; } } child.setTag(R.id.overlay_layout_params_backup, child.getLayoutParams()); addView(child, initParams(child, left, top)); invalidate(); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { // Intercept and noop all touch events - overlays do not allow touch events return false; } @Override public void removeView(View view) { super.removeView(view); ViewUtils.setLayoutParamsSilently(view, (ViewGroup.LayoutParams) view.getTag(R.id.overlay_layout_params_backup)); view.setTag(R.id.overlay_layout_params_backup, null); } public void moveView(View view, int left, int top) { if (view.getParent() == this) { view.setLayoutParams(initParams(view, left, top)); } } private LayoutParams initParams(View view, int left, int top) { int[] loc = new int[2]; getLocationOnScreen(loc); final LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); left -= loc[0]; top -= loc[1]; layoutParams.leftMargin = left; layoutParams.topMargin = top; view.setLeft(left); view.setTop(top); if (view.getMeasuredWidth() != 0) { layoutParams.width = view.getMeasuredWidth(); view.setRight(left + layoutParams.width); } if (view.getMeasuredHeight() != 0) { layoutParams.height = view.getMeasuredHeight(); view.setBottom(top + layoutParams.height); } return layoutParams; } public synchronized void addDrawable(Drawable drawable) { if (drawable != null) { this.mDrawableOverlays.add(drawable); invalidate(); } } public synchronized void removeDrawable(Drawable drawable) { mDrawableOverlays.remove(drawable); invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for (Drawable drawable : mDrawableOverlays) { drawable.draw(canvas); } } public static ViewOverlayPreJellybean getOverlay(ViewGroup sceneRoot) { if (sceneRoot != null) { ViewGroup group = sceneRoot; while (group.getId() != android.R.id.content && group.getParent() != null && group.getParent() instanceof ViewGroup) { group = (ViewGroup) group.getParent(); } for (int i = 0; i < group.getChildCount(); i++) { View child = group.getChildAt(i); if (child instanceof ViewOverlayPreJellybean) { return (ViewOverlayPreJellybean) child; } } final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); params.gravity = Gravity.FILL; ViewOverlayPreJellybean viewOverlay = new ViewOverlayPreJellybean(sceneRoot.getContext()); group.addView(viewOverlay, params); return viewOverlay; } else { return null; } } }