Skip to content

Commit

Permalink
Fixes #19 by adding an alternative method for determining when the vi…
Browse files Browse the repository at this point in the history
…ew has been laid out
  • Loading branch information
mattsilber committed Dec 15, 2023
1 parent a10c0b4 commit e2d409a
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 29 deletions.
2 changes: 1 addition & 1 deletion scratchoff-sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ android {
defaultConfig {
applicationId "com.jackpocket.scratchoff.test"

minSdkVersion 14
minSdkVersion 16
targetSdkVersion rootProject.ext.targetSdkVersion

versionCode 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class MainActivity: AppCompatActivity(), ScratchoffController.ThresholdChangedLi
.setClearAnimationEnabled(true)
.setClearAnimationDuration(1, TimeUnit.SECONDS)
.setClearAnimationInterpolator(LinearInterpolator())
.setUsePreDrawForLayoutEnabled(true)
// .setTouchRadiusPx(25)
// .setThresholdAccuracyQuality(Quality.LOW)
// .setThresholdTargetRegionsProvider({
Expand Down
2 changes: 1 addition & 1 deletion scratchoff/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ android {
buildToolsVersion = rootProject.ext.buildToolsVersion

defaultConfig {
minSdkVersion 14
minSdkVersion 16
targetSdkVersion rootProject.ext.targetSdkVersion

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
Expand Down Expand Up @@ -59,6 +58,8 @@ public interface Delegate {

private Long activeClearTag = 0L;

private boolean usePreDrawForLayoutEnabled = false;

public ScratchableLayoutDrawer(Delegate delegate) {
this.delegate = new WeakReference<>(delegate);
}
Expand Down Expand Up @@ -120,7 +121,7 @@ protected void enqueueViewInitializationOnGlobalLayout(final View scratchView, f
return;
}

addGlobalLayoutRequest(
deferRunnableUntilViewIsLaidOut(
behindView,
new Runnable() {
public void run() {
Expand All @@ -141,7 +142,7 @@ protected void performLayoutDimensionMatching(final View scratchView, final View

@SuppressWarnings("WeakerAccess")
protected void enqueueScratchableViewInitializationOnGlobalLayout(final View scratchView) {
addGlobalLayoutRequest(
deferRunnableUntilViewIsLaidOut(
scratchView,
new Runnable() {
public void run() {
Expand Down Expand Up @@ -345,31 +346,49 @@ protected void hideAndMarkScratchableSurfaceViewCleared() {
visibilityController.showChildren(view);
}

private void addGlobalLayoutRequest(final View view, final Runnable runnable) {
view.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
if(runnable != null)
runnable.run();

removeGlobalLayoutListener(view, this);
}
});

view.requestLayout();
}

@SuppressWarnings({"deprecation", "RedundantSuppression"})
private void removeGlobalLayoutListener(View view, ViewTreeObserver.OnGlobalLayoutListener listener) {
if (Build.VERSION.SDK_INT < 16) {
view.getViewTreeObserver()
.removeGlobalOnLayoutListener(listener);

return;
private void deferRunnableUntilViewIsLaidOut(final View view, final Runnable runnable) {
if (usePreDrawForLayoutEnabled) {
view
.getViewTreeObserver()
.addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (runnable != null) {
runnable.run();
}


view
.getViewTreeObserver()
.removeOnPreDrawListener(this);

return true;
}
}
);
}
else {
view
.getViewTreeObserver()
.addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (runnable != null) {
runnable.run();
}


view
.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
}
}
);
}

view.getViewTreeObserver()
.removeOnGlobalLayoutListener(listener);
view.requestLayout();
}

@SuppressWarnings("WeakerAccess")
Expand All @@ -385,4 +404,11 @@ public ScratchableLayoutDrawer setClearAnimationInterpolator(Interpolator clearA

return this;
}

@SuppressWarnings("WeakerAccess")
public ScratchableLayoutDrawer setUsePreDrawForLayoutEnabled(boolean usePreDrawForLayoutEnabled) {
this.usePreDrawForLayoutEnabled = usePreDrawForLayoutEnabled;

return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ public interface ThresholdChangedListener {
private final LinkedBlockingQueue<ScratchPathPoint> history = new LinkedBlockingQueue<ScratchPathPoint>();
private boolean stateRestorationEnabled;

private boolean usePreDrawForLayoutEnabled = false;

/**
* Create a new {@link ScratchoffController} instance targeting a scratchable layout.
*/
Expand Down Expand Up @@ -151,7 +153,8 @@ public ScratchoffController attach() {
protected ScratchableLayoutDrawer createLayoutDrawer() {
return new ScratchableLayoutDrawer(this)
.setClearAnimationDurationMs(clearAnimationDurationMs)
.setClearAnimationInterpolator(clearAnimationInterpolator);
.setClearAnimationInterpolator(clearAnimationInterpolator)
.setUsePreDrawForLayoutEnabled(usePreDrawForLayoutEnabled);
}

protected ScratchoffThresholdProcessor createThresholdProcessor() {
Expand Down Expand Up @@ -467,6 +470,20 @@ public ScratchoffController setStateRestorationEnabled(boolean stateRestorationE
return this;
}

/**
* Set whether or not to use the new {@link android.view.ViewTreeObserver.OnPreDrawListener}
* code paths to determine the layout sizing, instead of the original
* {@link android.view.ViewTreeObserver.OnGlobalLayoutListener} implementation.
* This is in attempt to fix #19 caused by the width or height of the View being
* zero when attempting to create the scratchable {@link Bitmap} instances.
* The default for this value is false for the original (crashing) behavior.
*/
public ScratchoffController setUsePreDrawForLayoutEnabled(boolean usePreDrawForLayoutEnabled) {
this.usePreDrawForLayoutEnabled = usePreDrawForLayoutEnabled;

return this;
}

public View getViewBehind() {
return behindView.get();
}
Expand Down

0 comments on commit e2d409a

Please sign in to comment.