Put imageviewer in a navigationcontroller and some cleanup

tempwork
Floens 10 years ago
parent 2ae40e97f7
commit cf7af07382
  1. 27
      Clover/app/src/main/java/org/floens/chan/controller/NavigationController.java
  2. 9
      Clover/app/src/main/java/org/floens/chan/ui/activity/BoardActivity.java
  3. 180
      Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java
  4. 43
      Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerNavigationController.java
  5. 5
      Clover/app/src/main/java/org/floens/chan/ui/controller/RootNavigationController.java
  6. 19
      Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java
  7. 4
      Clover/app/src/main/java/org/floens/chan/ui/view/ClippingImageView.java
  8. 1
      Clover/app/src/main/res/layout/controller_image_viewer.xml
  9. 0
      Clover/app/src/main/res/layout/controller_navigation_drawer.xml
  10. 37
      Clover/app/src/main/res/layout/controller_navigation_image_viewer.xml

@ -19,7 +19,6 @@ package org.floens.chan.controller;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.support.v4.widget.DrawerLayout;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import org.floens.chan.ui.toolbar.Toolbar; import org.floens.chan.ui.toolbar.Toolbar;
@ -30,8 +29,6 @@ import java.util.List;
public abstract class NavigationController extends Controller implements ControllerTransition.Callback, Toolbar.ToolbarCallback { public abstract class NavigationController extends Controller implements ControllerTransition.Callback, Toolbar.ToolbarCallback {
public Toolbar toolbar; public Toolbar toolbar;
public FrameLayout container; public FrameLayout container;
public DrawerLayout drawerLayout;
public FrameLayout drawer;
private List<Controller> controllerList = new ArrayList<>(); private List<Controller> controllerList = new ArrayList<>();
private ControllerTransition controllerTransition; private ControllerTransition controllerTransition;
@ -41,6 +38,15 @@ public abstract class NavigationController extends Controller implements Control
super(context); super(context);
} }
@Override
public void onDestroy() {
super.onDestroy();
while (controllerList.size() > 0) {
popController(false);
}
}
public boolean pushController(final Controller to) { public boolean pushController(final Controller to) {
return pushController(to, true); return pushController(to, true);
} }
@ -92,12 +98,12 @@ public abstract class NavigationController extends Controller implements Control
throw new IllegalArgumentException("Cannot pop controller while a transition is in progress."); throw new IllegalArgumentException("Cannot pop controller while a transition is in progress.");
} }
if (controllerList.size() == 1) { if (controllerList.size() == 0) {
throw new IllegalArgumentException("Cannot pop with 1 controller left"); throw new IllegalArgumentException("Cannot pop with no controllers left");
} }
final Controller from = controllerList.get(controllerList.size() - 1); final Controller from = controllerList.get(controllerList.size() - 1);
final Controller to = controllerList.get(controllerList.size() - 2); final Controller to = controllerList.size() > 1 ? controllerList.get(controllerList.size() - 2) : null;
if (controllerTransition != null) { if (controllerTransition != null) {
blockingInput = true; blockingInput = true;
@ -105,17 +111,18 @@ public abstract class NavigationController extends Controller implements Control
controllerTransition.setCallback(this); controllerTransition.setCallback(this);
ControllerLogic.startTransition(from, to, true, false, container, controllerTransition); ControllerLogic.startTransition(from, to, true, false, container, controllerTransition);
if (to != null) {
toolbar.setNavigationItem(true, false, to.navigationItem); toolbar.setNavigationItem(true, false, to.navigationItem);
}
} else { } else {
ControllerLogic.transition(from, to, true, false, container); ControllerLogic.transition(from, to, true, false, container);
if (to != null) {
toolbar.setNavigationItem(false, false, to.navigationItem); toolbar.setNavigationItem(false, false, to.navigationItem);
} }
controllerList.remove(from);
return true;
} }
public void setControllerList(List<Controller> controllers) { return true;
} }
@Override @Override

@ -88,10 +88,19 @@ public class BoardActivity extends Activity {
@Override @Override
public void onBackPressed() { public void onBackPressed() {
if (!stackTop().onBack()) { if (!stackTop().onBack()) {
// Don't destroy the view, let Android do that or it'll create artifacts
stackTop().onHide();
super.onBackPressed(); super.onBackPressed();
} }
} }
@Override
protected void onDestroy() {
super.onDestroy();
stackTop().onDestroy();
}
private Controller stackTop() { private Controller stackTop() {
return stack.get(stack.size() - 1); return stack.get(stack.size() - 1);
} }

@ -20,23 +20,24 @@ import org.floens.chan.R;
import org.floens.chan.controller.Controller; import org.floens.chan.controller.Controller;
import org.floens.chan.ui.view.ClippingImageView; import org.floens.chan.ui.view.ClippingImageView;
import org.floens.chan.utils.AnimationUtils; import org.floens.chan.utils.AnimationUtils;
import org.floens.chan.utils.Logger;
import static org.floens.chan.utils.AndroidUtils.dp; import static org.floens.chan.utils.AndroidUtils.dp;
import static org.floens.chan.utils.AnimationUtils.calculateBoundsAnimation; import static org.floens.chan.utils.AnimationUtils.calculateBoundsAnimation;
public class ImageViewController extends Controller implements View.OnClickListener { public class ImageViewerController extends Controller implements View.OnClickListener {
private static final int DURATION = 165; private static final int TRANSITION_DURATION = 200; //165;
private static final float CLIP_DURATION_PERCENTAGE = 0.40f; private static final int TRANSITION_CLIP_DURATION = (int) (TRANSITION_DURATION * 0.5f);
private static final float FINAL_ALPHA = 0.80f; private static final float TRANSITION_FINAL_ALPHA = 0.80f;
private ClippingImageView imageView; private ClippingImageView previewImage;
private Callback callback; private Callback callback;
private int statusBarColorPrevious; private int statusBarColorPrevious;
private AnimatorSet startAnimation; private AnimatorSet startPreviewAnimation;
private AnimatorSet endAnimation; private AnimatorSet endAnimation;
public ImageViewController(Context context) { public ImageViewerController(Context context) {
super(context); super(context);
} }
@ -44,62 +45,59 @@ public class ImageViewController extends Controller implements View.OnClickListe
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
view = inflateRes(R.layout.controller_view_image); view = inflateRes(R.layout.controller_image_viewer);
previewImage = (ClippingImageView) view.findViewById(R.id.image);
imageView = (ClippingImageView) view.findViewById(R.id.image);
view.setOnClickListener(this); view.setOnClickListener(this);
} }
@Override @Override
public boolean onBack() { public void onClick(View v) {
removeImage(); startPreviewOutTransition();
return true;
} }
@Override @Override
public void onClick(View v) { public boolean onBack() {
removeImage(); startPreviewOutTransition();
return true;
} }
public void setImage(Callback callback, final ImageView startImageView) { public void startPreviewInTransition(Callback callback, final ImageView previewImageView) {
this.callback = callback; this.callback = callback;
imageView.setImageDrawable(startImageView.getDrawable()); previewImage.setImageDrawable(previewImageView.getDrawable());
Rect startBounds = getStartImageViewBounds(startImageView); Rect startBounds = getImageViewBounds(previewImageView);
final Rect endBounds = new Rect(); final Rect endBounds = new Rect();
final Point globalOffset = new Point(); final Point globalOffset = new Point();
view.getGlobalVisibleRect(endBounds, globalOffset); view.getGlobalVisibleRect(endBounds, globalOffset);
float startScale = calculateBoundsAnimation(startBounds, endBounds, globalOffset); float startScale = calculateBoundsAnimation(startBounds, endBounds, globalOffset);
imageView.setPivotX(0f); previewImage.setPivotX(0f);
imageView.setPivotY(0f); previewImage.setPivotY(0f);
imageView.setX(startBounds.left); previewImage.setX(startBounds.left);
imageView.setY(startBounds.top); previewImage.setY(startBounds.top);
imageView.setScaleX(startScale); previewImage.setScaleX(startScale);
imageView.setScaleY(startScale); previewImage.setScaleY(startScale);
Rect clipStartBounds = new Rect(0, 0, (int) (startImageView.getWidth() / startScale), (int) (startImageView.getHeight() / startScale)); Rect clipStartBounds = new Rect(0, 0, (int) (previewImageView.getWidth() / startScale), (int) (previewImageView.getHeight() / startScale));
Window window = ((Activity) context).getWindow();
if (Build.VERSION.SDK_INT >= 21) { if (Build.VERSION.SDK_INT >= 21) {
statusBarColorPrevious = window.getStatusBarColor(); statusBarColorPrevious = getWindow().getStatusBarColor();
} }
startAnimation(startBounds, endBounds, startScale, clipStartBounds); doPreviewInTransition(startBounds, endBounds, startScale, clipStartBounds);
} }
public void removeImage() { public void startPreviewOutTransition() {
if (startAnimation != null || endAnimation != null) { if (startPreviewAnimation != null || endAnimation != null) {
return; return;
} }
endAnimation(); doPreviewOutAnimation();
// endAnimationEmpty();
} }
private void startAnimation(Rect startBounds, Rect finalBounds, float startScale, final Rect clipStartBounds) { private void doPreviewInTransition(Rect startBounds, Rect finalBounds, float startScale, final Rect clipStartBounds) {
startAnimation = new AnimatorSet(); startPreviewAnimation = new AnimatorSet();
ValueAnimator backgroundAlpha = ValueAnimator.ofFloat(0f, 1f); ValueAnimator backgroundAlpha = ValueAnimator.ofFloat(0f, 1f);
backgroundAlpha.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { backgroundAlpha.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@ -114,42 +112,39 @@ public class ImageViewController extends Controller implements View.OnClickListe
clip.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { clip.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override @Override
public void onAnimationUpdate(ValueAnimator animation) { public void onAnimationUpdate(ValueAnimator animation) {
AnimationUtils.getClippingBounds(clipStartBounds, imageView, clipRect, (float) animation.getAnimatedValue()); AnimationUtils.getClippingBounds(clipStartBounds, previewImage, clipRect, (float) animation.getAnimatedValue());
imageView.clip(clipRect); previewImage.clip(clipRect);
} }
}); });
startAnimation startPreviewAnimation
.play(ObjectAnimator.ofFloat(imageView, View.X, startBounds.left, finalBounds.left).setDuration(DURATION)) .play(ObjectAnimator.ofFloat(previewImage, View.X, startBounds.left, finalBounds.left).setDuration(TRANSITION_DURATION))
.with(ObjectAnimator.ofFloat(imageView, View.Y, startBounds.top, finalBounds.top).setDuration(DURATION)) .with(ObjectAnimator.ofFloat(previewImage, View.Y, startBounds.top, finalBounds.top).setDuration(TRANSITION_DURATION))
.with(ObjectAnimator.ofFloat(imageView, View.SCALE_X, startScale, 1f).setDuration(DURATION)) .with(ObjectAnimator.ofFloat(previewImage, View.SCALE_X, startScale, 1f).setDuration(TRANSITION_DURATION))
.with(ObjectAnimator.ofFloat(imageView, View.SCALE_Y, startScale, 1f).setDuration(DURATION)) .with(ObjectAnimator.ofFloat(previewImage, View.SCALE_Y, startScale, 1f).setDuration(TRANSITION_DURATION))
.with(backgroundAlpha.setDuration(DURATION)) .with(backgroundAlpha.setDuration(TRANSITION_DURATION))
.with(clip.setDuration((long) (DURATION * CLIP_DURATION_PERCENTAGE))); .with(clip.setDuration(TRANSITION_CLIP_DURATION));
startAnimation.setInterpolator(new DecelerateInterpolator()); startPreviewAnimation.setInterpolator(new DecelerateInterpolator());
startAnimation.addListener(new AnimatorListenerAdapter() { startPreviewAnimation.addListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
startAnimationEnd(); previewImage.setX(0f);
startAnimation = null; previewImage.setY(0f);
previewImage.setScaleX(1f);
previewImage.setScaleY(1f);
previewImage.clip(null);
startPreviewAnimation = null;
} }
}); });
startAnimation.start(); startPreviewAnimation.start();
}
private void startAnimationEnd() {
imageView.setX(0f);
imageView.setY(0f);
imageView.setScaleX(1f);
imageView.setScaleY(1f);
} }
private void endAnimation() { private void doPreviewOutAnimation() {
ImageView startImage = getStartImageView(); ImageView startImage = getStartImageView();
Rect startBounds = null; Rect startBounds = null;
if (startImage != null) { if (startImage != null) {
startBounds = getStartImageViewBounds(startImage); startBounds = getImageViewBounds(startImage);
} }
if (startBounds == null) { if (startBounds == null) {
endAnimation = new AnimatorSet(); endAnimation = new AnimatorSet();
@ -163,16 +158,16 @@ public class ImageViewController extends Controller implements View.OnClickListe
}); });
endAnimation endAnimation
.play(ObjectAnimator.ofFloat(imageView, View.Y, imageView.getTop(), imageView.getTop() + dp(20))) .play(ObjectAnimator.ofFloat(previewImage, View.Y, previewImage.getTop(), previewImage.getTop() + dp(20)))
.with(ObjectAnimator.ofFloat(imageView, View.ALPHA, 1f, 0f)) .with(ObjectAnimator.ofFloat(previewImage, View.ALPHA, 1f, 0f))
.with(backgroundAlpha); .with(backgroundAlpha);
endAnimation.setDuration(DURATION); endAnimation.setDuration(TRANSITION_DURATION);
endAnimation.setInterpolator(new DecelerateInterpolator()); endAnimation.setInterpolator(new DecelerateInterpolator());
endAnimation.addListener(new AnimatorListenerAdapter() { endAnimation.addListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
endAnimationEnd(); previewOutAnimationEnded();
} }
}); });
endAnimation.start(); endAnimation.start();
@ -198,75 +193,84 @@ public class ImageViewController extends Controller implements View.OnClickListe
clip.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { clip.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override @Override
public void onAnimationUpdate(ValueAnimator animation) { public void onAnimationUpdate(ValueAnimator animation) {
AnimationUtils.getClippingBounds(clipStartBounds, imageView, clipRect, (float) animation.getAnimatedValue()); AnimationUtils.getClippingBounds(clipStartBounds, previewImage, clipRect, (float) animation.getAnimatedValue());
imageView.clip(clipRect); previewImage.clip(clipRect);
} }
}); });
long clipDuration = (long) (DURATION * CLIP_DURATION_PERCENTAGE); clip.setStartDelay(TRANSITION_DURATION - TRANSITION_CLIP_DURATION);
clip.setStartDelay(DURATION - clipDuration); clip.setDuration(TRANSITION_CLIP_DURATION);
clip.setDuration(clipDuration);
endAnimation endAnimation
.play(ObjectAnimator.ofFloat(imageView, View.X, startBounds.left).setDuration(DURATION)) .play(ObjectAnimator.ofFloat(previewImage, View.X, startBounds.left).setDuration(TRANSITION_DURATION))
.with(ObjectAnimator.ofFloat(imageView, View.Y, startBounds.top).setDuration(DURATION)) .with(ObjectAnimator.ofFloat(previewImage, View.Y, startBounds.top).setDuration(TRANSITION_DURATION))
.with(ObjectAnimator.ofFloat(imageView, View.SCALE_X, 1f, startScale).setDuration(DURATION)) .with(ObjectAnimator.ofFloat(previewImage, View.SCALE_X, 1f, startScale).setDuration(TRANSITION_DURATION))
.with(ObjectAnimator.ofFloat(imageView, View.SCALE_Y, 1f, startScale).setDuration(DURATION)) .with(ObjectAnimator.ofFloat(previewImage, View.SCALE_Y, 1f, startScale).setDuration(TRANSITION_DURATION))
.with(backgroundAlpha.setDuration(DURATION)) .with(backgroundAlpha.setDuration(TRANSITION_DURATION))
.with(clip); .with(clip);
endAnimation.setInterpolator(new DecelerateInterpolator()); endAnimation.setInterpolator(new DecelerateInterpolator());
endAnimation.addListener(new AnimatorListenerAdapter() { endAnimation.addListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
endAnimationEnd(); previewOutAnimationEnded();
} }
}); });
endAnimation.start(); endAnimation.start();
} }
} }
private void endAnimationEnd() { private void previewOutAnimationEnded() {
Window window = ((Activity) context).getWindow(); setStatusBarColor(statusBarColorPrevious);
if (Build.VERSION.SDK_INT >= 21) {
window.setStatusBarColor(statusBarColorPrevious);
}
callback.onImageViewLayoutDestroy(this); callback.onPreviewDestroy(this);
stopPresenting(false); navigationController.stopPresenting(false);
} }
private void setBackgroundAlpha(float alpha) { private void setBackgroundAlpha(float alpha) {
alpha = alpha * FINAL_ALPHA; alpha *= TRANSITION_FINAL_ALPHA;
view.setBackgroundColor(Color.argb((int) (alpha * 255f), 0, 0, 0)); view.setBackgroundColor(Color.argb((int) (alpha * 255f), 0, 0, 0));
if (Build.VERSION.SDK_INT >= 21) { if (Build.VERSION.SDK_INT >= 21) {
Window window = ((Activity) context).getWindow();
int r = (int) ((1f - alpha) * Color.red(statusBarColorPrevious)); int r = (int) ((1f - alpha) * Color.red(statusBarColorPrevious));
int g = (int) ((1f - alpha) * Color.green(statusBarColorPrevious)); int g = (int) ((1f - alpha) * Color.green(statusBarColorPrevious));
int b = (int) ((1f - alpha) * Color.blue(statusBarColorPrevious)); int b = (int) ((1f - alpha) * Color.blue(statusBarColorPrevious));
window.setStatusBarColor(Color.argb(255, r, g, b)); setStatusBarColor(Color.argb(255, r, g, b));
}
}
private void setStatusBarColor(int color) {
if (Build.VERSION.SDK_INT >= 21) {
getWindow().setStatusBarColor(color);
} }
} }
private Rect getStartImageViewBounds(ImageView image) { private Rect getImageViewBounds(ImageView image) {
Rect startBounds = new Rect(); Rect startBounds = new Rect();
if (image.getGlobalVisibleRect(startBounds)) { if (image.getGlobalVisibleRect(startBounds) && !startBounds.isEmpty()) {
AnimationUtils.adjustImageViewBoundsToDrawableBounds(image, startBounds); AnimationUtils.adjustImageViewBoundsToDrawableBounds(image, startBounds);
if (!startBounds.isEmpty()) {
Logger.test(startBounds.toShortString());
return startBounds; return startBounds;
} else { } else {
return null; return null;
} }
} else {
return null;
}
} }
private ImageView getStartImageView() { private ImageView getStartImageView() {
return callback.getImageView(this); return callback.getPreviewImageStartView(this);
}
private Window getWindow() {
return ((Activity) context).getWindow();
} }
public interface Callback { public interface Callback {
public ImageView getImageView(ImageViewController imageViewController); public ImageView getPreviewImageStartView(ImageViewerController imageViewerController);
public void onImageViewLayoutDestroy(ImageViewController imageViewController); public void onPreviewDestroy(ImageViewerController imageViewerController);
} }
} }

@ -0,0 +1,43 @@
package org.floens.chan.ui.controller;
import android.content.Context;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import org.floens.chan.R;
import org.floens.chan.controller.NavigationController;
import org.floens.chan.ui.toolbar.Toolbar;
import org.floens.chan.utils.AndroidUtils;
public class ImageViewerNavigationController extends NavigationController {
private ImageViewerController imageViewerController;
public ImageViewerNavigationController(Context context) {
super(context);
}
@Override
public void onCreate() {
super.onCreate();
view = inflateRes(R.layout.controller_navigation_image_viewer);
toolbar = (Toolbar) view.findViewById(R.id.toolbar);
container = (FrameLayout) view.findViewById(R.id.container);
toolbar.setCallback(this);
imageViewerController = new ImageViewerController(context);
pushController(imageViewerController, false);
}
public void setImage(final ImageViewerController.Callback callback, final ImageView startImageView) {
AndroidUtils.waitForMeasure(imageViewerController.view, new AndroidUtils.OnMeasuredCallback() {
@Override
public boolean onMeasured(View view) {
imageViewerController.startPreviewInTransition(callback, startImageView);
return true;
}
});
}
}

@ -31,6 +31,9 @@ import org.floens.chan.utils.AndroidUtils;
import static org.floens.chan.utils.AndroidUtils.dp; import static org.floens.chan.utils.AndroidUtils.dp;
public class RootNavigationController extends NavigationController { public class RootNavigationController extends NavigationController {
public DrawerLayout drawerLayout;
public FrameLayout drawer;
public RootNavigationController(Context context) { public RootNavigationController(Context context) {
super(context); super(context);
} }
@ -39,7 +42,7 @@ public class RootNavigationController extends NavigationController {
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
view = inflateRes(R.layout.root_layout); view = inflateRes(R.layout.controller_navigation_drawer);
toolbar = (Toolbar) view.findViewById(R.id.toolbar); toolbar = (Toolbar) view.findViewById(R.id.toolbar);
container = (FrameLayout) view.findViewById(R.id.container); container = (FrameLayout) view.findViewById(R.id.container);
drawerLayout = (DrawerLayout) view.findViewById(R.id.drawer_layout); drawerLayout = (DrawerLayout) view.findViewById(R.id.drawer_layout);

@ -7,11 +7,10 @@ import android.widget.ImageView;
import org.floens.chan.controller.Controller; import org.floens.chan.controller.Controller;
import org.floens.chan.core.model.PostImage; import org.floens.chan.core.model.PostImage;
import org.floens.chan.ui.layout.ThreadLayout; import org.floens.chan.ui.layout.ThreadLayout;
import org.floens.chan.utils.AndroidUtils;
import java.util.List; import java.util.List;
public abstract class ThreadController extends Controller implements ThreadLayout.ThreadLayoutCallback, ImageViewController.Callback { public abstract class ThreadController extends Controller implements ThreadLayout.ThreadLayoutCallback, ImageViewerController.Callback {
protected ThreadLayout threadLayout; protected ThreadLayout threadLayout;
private ImageView presentingImageView; private ImageView presentingImageView;
@ -28,24 +27,18 @@ public abstract class ThreadController extends Controller implements ThreadLayou
presentingImageView = thumbnail; presentingImageView = thumbnail;
presentingImageView.setVisibility(View.INVISIBLE); presentingImageView.setVisibility(View.INVISIBLE);
final ImageViewController imageViewController = new ImageViewController(context); final ImageViewerNavigationController imageViewerNavigationController = new ImageViewerNavigationController(context);
presentController(imageViewController, false); presentController(imageViewerNavigationController, false);
AndroidUtils.waitForMeasure(imageViewController.view, new AndroidUtils.OnMeasuredCallback() { imageViewerNavigationController.setImage(this, thumbnail);
@Override
public boolean onMeasured(View view) {
imageViewController.setImage(ThreadController.this, thumbnail);
return true;
}
});
} }
@Override @Override
public ImageView getImageView(ImageViewController imageViewController) { public ImageView getPreviewImageStartView(ImageViewerController imageViewerController) {
return presentingImageView; return presentingImageView;
} }
@Override @Override
public void onImageViewLayoutDestroy(ImageViewController imageViewController) { public void onPreviewDestroy(ImageViewerController imageViewerController) {
presentingImageView.setVisibility(View.VISIBLE); presentingImageView.setVisibility(View.VISIBLE);
presentingImageView = null; presentingImageView = null;
} }

@ -31,7 +31,11 @@ public class ClippingImageView extends ImageView {
} }
public void clip(Rect rect) { public void clip(Rect rect) {
if (rect == null) {
clipRect.setEmpty();
} else {
clipRect.set(rect); clipRect.set(rect);
}
invalidate(); invalidate();
} }
} }

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?><!--
Clover - 4chan browser https://github.com/Floens/Clover/
Copyright (C) 2014 Floens
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<org.floens.chan.ui.toolbar.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="@color/primary"
android:elevation="4dp" />
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
Loading…
Cancel
Save