Created
April 8, 2016 00:52
-
-
Save NikolaDespotoski/1fa18066c72e4f5ac11c85d40d14c34c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.content.res.TypedArray; | |
import android.os.Parcelable; | |
import android.support.annotation.NonNull; | |
import android.support.design.widget.CoordinatorLayout; | |
import android.support.v4.view.WindowInsetsCompat; | |
import android.text.TextUtils; | |
import android.util.AttributeSet; | |
import android.view.MotionEvent; | |
import android.view.View; | |
import java.lang.reflect.Constructor; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
/** | |
* Created by Nikola on 4/8/2016. | |
*/ | |
public class MultiCoordinatorLayoutBehavior<V extends View> extends CoordinatorLayout.Behavior<V> { | |
static final Class<?>[] CONSTRUCTOR_PARAMS = new Class<?>[]{ | |
Context.class, | |
AttributeSet.class | |
}; | |
static final ThreadLocal<Map<String, Constructor<CoordinatorLayout.Behavior>>> sConstructors = | |
new ThreadLocal<>(); | |
static final ThreadLocal<Map<CoordinatorLayout.Behavior, List<Method>>> sMethod = | |
new ThreadLocal<>(); | |
private List<CoordinatorLayout.Behavior> mBehaviors = new ArrayList<>(); | |
public MultiCoordinatorLayoutBehavior() { | |
super(); | |
} | |
public MultiCoordinatorLayoutBehavior(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
TypedArray a = context.obtainStyledAttributes(attrs, | |
R.styleable.MultiCoordinatorLayoutBehavior); | |
int resourceId = a.getResourceId(R.styleable.MultiCoordinatorLayoutBehavior_behaviors, 0); | |
a.recycle(); | |
if (resourceId != 0) { | |
String[] stringArray = context.getResources().getStringArray(resourceId); | |
insantiateBehaviors(context, attrs, stringArray); | |
} | |
} | |
static CoordinatorLayout.Behavior parseBehavior(Context context, AttributeSet attrs, String name) { | |
if (TextUtils.isEmpty(name)) { | |
return null; | |
} | |
final String fullName; | |
if (name.startsWith(".")) { | |
fullName = context.getPackageName() + name; | |
} else if (name.indexOf('.') >= 0) { | |
fullName = name; | |
} else { | |
fullName = '.' + name; | |
} | |
try { | |
Map<String, Constructor<CoordinatorLayout.Behavior>> constructors = sConstructors.get(); | |
if (constructors == null) { | |
constructors = new HashMap<>(); | |
sConstructors.set(constructors); | |
} | |
Constructor<CoordinatorLayout.Behavior> c = constructors.get(fullName); | |
if (c == null) { | |
final Class<CoordinatorLayout.Behavior> clazz = (Class<CoordinatorLayout.Behavior>) Class.forName(fullName, true, | |
context.getClassLoader()); | |
c = clazz.getConstructor(CONSTRUCTOR_PARAMS); | |
c.setAccessible(true); | |
constructors.put(fullName, c); | |
} | |
return c.newInstance(context, attrs); | |
} catch (Exception e) { | |
throw new RuntimeException("Could not inflate Behavior subclass " + fullName, e); | |
} | |
} | |
@Override | |
public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) { | |
return super.onSaveInstanceState(parent, child); | |
} | |
@Override | |
public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev) { | |
return super.onInterceptTouchEvent(parent, child, ev); | |
} | |
@Override | |
public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev) { | |
return super.onTouchEvent(parent, child, ev); | |
} | |
@Override | |
public int getScrimColor(CoordinatorLayout parent, V child) { | |
return super.getScrimColor(parent, child); | |
} | |
@Override | |
public float getScrimOpacity(CoordinatorLayout parent, V child) { | |
return super.getScrimOpacity(parent, child); | |
} | |
@Override | |
public boolean blocksInteractionBelow(CoordinatorLayout parent, V child) { | |
return super.blocksInteractionBelow(parent, child); | |
} | |
@Override | |
public boolean layoutDependsOn(CoordinatorLayout parent, V child, View dependency) { | |
return super.layoutDependsOn(parent, child, dependency); | |
} | |
@Override | |
public boolean onDependentViewChanged(CoordinatorLayout parent, V child, View dependency) { | |
return super.onDependentViewChanged(parent, child, dependency); | |
} | |
@Override | |
public void onDependentViewRemoved(CoordinatorLayout parent, V child, View dependency) { | |
super.onDependentViewRemoved(parent, child, dependency); | |
} | |
@Override | |
public boolean isDirty(CoordinatorLayout parent, V child) { | |
return super.isDirty(parent, child); | |
} | |
@Override | |
public boolean onMeasureChild(CoordinatorLayout parent, V child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { | |
return super.onMeasureChild(parent, child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed); | |
} | |
@Override | |
public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) { | |
return super.onLayoutChild(parent, child, layoutDirection); | |
} | |
@Override | |
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes) { | |
return super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes); | |
} | |
@Override | |
public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes) { | |
super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes); | |
} | |
@Override | |
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) { | |
super.onStopNestedScroll(coordinatorLayout, child, target); | |
} | |
@Override | |
public void onNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { | |
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed); | |
} | |
@Override | |
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed) { | |
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed); | |
} | |
@Override | |
public boolean onNestedFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, boolean consumed) { | |
invokeMethod("onNestedFling", coordinatorLayout, child, target, velocityX, velocityY, consumed); | |
return true; | |
} | |
@Override | |
public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY) { | |
return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY); | |
} | |
@Override | |
public WindowInsetsCompat onApplyWindowInsets(CoordinatorLayout coordinatorLayout, V child, WindowInsetsCompat insets) { | |
return super.onApplyWindowInsets(coordinatorLayout, child, insets); | |
} | |
@Override | |
public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) { | |
super.onRestoreInstanceState(parent, child, state); | |
} | |
private void insantiateBehaviors(Context context, AttributeSet attrs, @NonNull String[] behaviors) { | |
for (int i = behaviors.length - 1; i >= 0; i--) { | |
CoordinatorLayout.Behavior behavior = parseBehavior(context, attrs, behaviors[i]); | |
if (behavior != null) { | |
mBehaviors.add(behavior); | |
} | |
} | |
} | |
private void invokeMethod(String methodName, Object... params) { | |
for (int i = mBehaviors.size() - 1; i >= 0; i--) { | |
CoordinatorLayout.Behavior behavior = mBehaviors.get(i); | |
Map<CoordinatorLayout.Behavior, List<Method>> methodsMap = sMethod.get(); | |
List<Method> methods = methodsMap.get(behavior); | |
if (methods == null) { | |
methods = resolveAllMethods(behavior); | |
methodsMap.put(behavior, methods); | |
} | |
Method method = getMethod(methods, methodName); | |
if(method != null && method.isAccessible()){ | |
try { | |
method.invoke(behavior, params); | |
} catch (IllegalAccessException e) { | |
e.printStackTrace(); | |
} catch (InvocationTargetException e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
} | |
private List<Method> resolveAllMethods(CoordinatorLayout.Behavior behavior) { | |
Method[] declaredMethods = behavior.getClass().getDeclaredMethods(); | |
return Arrays.asList(declaredMethods); | |
} | |
private Method getMethod(List<Method> methods, String methodName) { | |
for (int i = methods.size() - 1; i >= 0; i--) { | |
Method method = methods.get(i); | |
if (method.getName().toLowerCase().equals(methodName)) return method; | |
} | |
return null; | |
} | |
<declare-styleable name="MultiCoordinatorLayoutBehavior"> | |
<attr name="behaviors" format="reference"/> | |
</declare-styleable> | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment