Improve Scene
This commit is contained in:
1 parent
c47b8a021e
commit
41ed55188b
22 files changed
+746
-584
No files matched your search
@@ -81,6 +81,12 @@ public class EhApplication extends SceneApplication {
|
||||
// TODO Can't create spider info dir
|
||||
}
|
||||
GallerySpider.init(mEhHttpClient, spiderInfoDir);
|
||||
|
||||
Settings.getImageDownloadLocation().ensureDir();
|
||||
Settings.getArchiveDownloadLocation().ensureDir();
|
||||
|
||||
|
||||
Settings.getImageDownloadLocation().listFiles();
|
||||
}
|
||||
|
||||
private int getMemoryCacheMaxSize() {
|
||||
|
||||
@@ -22,8 +22,7 @@ import android.util.Log;
|
||||
|
||||
import com.hippo.ehviewer.gallery.gifdecoder.GifDecoder;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
// TODO read file to memory or do jni
|
||||
public class GifTexture extends TiledTexture {
|
||||
|
||||
private static final String TAG = GifTexture.class.getSimpleName();
|
||||
@@ -33,7 +32,7 @@ public class GifTexture extends TiledTexture {
|
||||
|
||||
private GifDecoder mGifDecoder;
|
||||
private boolean mRunning = false;
|
||||
private final ReentrantLock mLock = new ReentrantLock();
|
||||
private volatile boolean mDecoding = false;
|
||||
|
||||
private GifDecodeTask mGifDecodeTask;
|
||||
|
||||
@@ -61,7 +60,7 @@ public class GifTexture extends TiledTexture {
|
||||
GifDecoder gifDecoder = mGifDecoder;
|
||||
|
||||
while (mRunning && sUploader != null) {
|
||||
mLock.lock();
|
||||
mDecoding = true;
|
||||
|
||||
gifDecoder.advance();
|
||||
Bitmap bitmap = gifDecoder.getNextFrame();
|
||||
@@ -83,9 +82,14 @@ public class GifTexture extends TiledTexture {
|
||||
if (mLastTime != 0) {
|
||||
delay -= time - mLastTime;
|
||||
}
|
||||
|
||||
|
||||
//Say.d(TAG, "time - mLastTime = " + (time - mLastTime));
|
||||
//Say.d(TAG, "gifDecoder.getNextDelay() = " + (gifDecoder.getNextDelay()));
|
||||
|
||||
mLastTime = time;
|
||||
|
||||
mLock.unlock();
|
||||
mDecoding = false;
|
||||
|
||||
if (delay > 5) {
|
||||
try {
|
||||
@@ -124,7 +128,7 @@ public class GifTexture extends TiledTexture {
|
||||
mRunning = false;
|
||||
mGifDecodeTask = null;
|
||||
|
||||
if (!mLock.isLocked()) {
|
||||
if (!mDecoding) {
|
||||
mGifDecoder.resetFrameIndex();
|
||||
mGifDecoder.advance();
|
||||
Bitmap bitmap = mGifDecoder.getNextFrame();
|
||||
@@ -142,7 +146,7 @@ public class GifTexture extends TiledTexture {
|
||||
public void recycle() {
|
||||
mRunning = false;
|
||||
|
||||
if (mLock.isLocked()) {
|
||||
if (mDecoding) {
|
||||
mGifDecodeTask.clearByMyself();
|
||||
} else {
|
||||
mGifDecoder.clear();
|
||||
|
||||
@@ -130,7 +130,9 @@ public class GLRootView extends GLSurfaceView
|
||||
// for example CyanogenMod use ro.opengles.surface.rgb565,
|
||||
// so just use default EGLConfigChooser.
|
||||
// And we do not need depth buffer
|
||||
setEGLConfigChooser(false);
|
||||
// TODO setEGLConfigChooser(8, 8, 8, 8, 0, 0) or setEGLConfigChooser(false)
|
||||
setEGLConfigChooser(8, 8, 8, 8, 0, 0);
|
||||
//setEGLConfigChooser(false);
|
||||
setRenderer(this);
|
||||
// setFormat is done by SurfaceView in SDK 2.3 and newer.
|
||||
//if (ApiHelper.USE_888_PIXEL_FORMAT) {
|
||||
|
||||
@@ -36,7 +36,6 @@ import com.hippo.ehviewer.widget.DrawerLeftPanel;
|
||||
import com.hippo.ehviewer.widget.FitStageLayout;
|
||||
import com.hippo.scene.Announcer;
|
||||
import com.hippo.scene.SceneManager;
|
||||
import com.hippo.scene.SimpleCurtain;
|
||||
import com.hippo.scene.StageActivity;
|
||||
import com.hippo.scene.StageLayout;
|
||||
import com.hippo.vectorold.content.VectorContext;
|
||||
@@ -87,7 +86,7 @@ public final class ContentActivity extends StageActivity
|
||||
break;
|
||||
case DRAWER_LIST_SETTINGS:
|
||||
mDrawerLayout.closeDrawers();
|
||||
startScene(MainSettingsScene.class, null, new SimpleCurtain(SimpleCurtain.DIRECTION_BOTTOM));
|
||||
startScene(MainSettingsScene.class);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -174,41 +173,6 @@ public final class ContentActivity extends StageActivity
|
||||
if (savedInstanceState == null) {
|
||||
startScene(GalleryListScene.class, null);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
try {
|
||||
|
||||
BitmapPool bitmapPool = new BitmapPool();
|
||||
ByteArrayPool byteArrayPool = new ByteArrayPool();
|
||||
GifBitmapProvider gifBitmapProvider = new GifBitmapProvider(bitmapPool, byteArrayPool);
|
||||
|
||||
|
||||
File file = new File(Environment.getExternalStorageDirectory(), "00000001.gif");
|
||||
UniRandomReadFile randomReadFile = UniRandomReadFile.fromFile(file);
|
||||
GifHeader gifHeader = new GifHeaderParser().setData(randomReadFile).parseHeader();
|
||||
if (gifHeader.getStatus() == GifDecoder.STATUS_OK) {
|
||||
GifDecoder gifDecoder = new GifDecoder(gifBitmapProvider, gifHeader, randomReadFile);
|
||||
|
||||
|
||||
for (int i = 0, n = gifDecoder.getFrameCount(); i < n * 2; i++) {
|
||||
gifDecoder.advance();
|
||||
gifDecoder.getNextFrame().compress(Bitmap.CompressFormat.PNG, 100, new FileOutputStream(new File(Environment.getExternalStorageDirectory(), String.format("%08d", i) + ".png")));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -267,7 +231,7 @@ public final class ContentActivity extends StageActivity
|
||||
@Override
|
||||
public void onClickSignIn() {
|
||||
mDrawerLayout.closeDrawers();
|
||||
startScene(SignInScene.class, null, new SimpleCurtain(SimpleCurtain.DIRECTION_BOTTOM));
|
||||
startScene(SignInScene.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -56,9 +56,11 @@ import com.hippo.ehviewer.widget.RatingView;
|
||||
import com.hippo.miscellaneous.StartActivityHelper;
|
||||
import com.hippo.rippleold.RippleSalon;
|
||||
import com.hippo.scene.Announcer;
|
||||
import com.hippo.scene.OffsetCurtain;
|
||||
import com.hippo.scene.RippleCurtain;
|
||||
import com.hippo.scene.Scene;
|
||||
import com.hippo.scene.SimpleDialog;
|
||||
import com.hippo.scene.UnionCurtain;
|
||||
import com.hippo.util.URLImageGetter;
|
||||
import com.hippo.widget.AccurateClick;
|
||||
import com.hippo.widget.AutoWrapLayout;
|
||||
@@ -136,6 +138,48 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener,
|
||||
client.execute(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(boolean rebirth) {
|
||||
super.onCreate(rebirth);
|
||||
setContentView(R.layout.scene_gallery_detail);
|
||||
|
||||
mDetailFrameLayout = (FrameLayout) findViewById(R.id.detail_frame_layout);
|
||||
|
||||
mHeader = (ViewGroup) findViewById(R.id.header);
|
||||
mThumb = (LoadImageView) mHeader.findViewById(R.id.thumb);
|
||||
mTitle = (TextView) mHeader.findViewById(R.id.title);
|
||||
mUploader = (TextView) mHeader.findViewById(R.id.uploader);
|
||||
mCategory = (TextView) mHeader.findViewById(R.id.category);
|
||||
|
||||
mActionCard = (ViewGroup) findViewById(R.id.action_card);
|
||||
mRead = mActionCard.findViewById(R.id.read);
|
||||
mDownload = mActionCard.findViewById(R.id.download);
|
||||
|
||||
mContent = (ViewGroup) findViewById(R.id.content);
|
||||
mInfo = (ViewGroup) mContent.findViewById(R.id.info);
|
||||
mLanguage = (TextView) mInfo.findViewById(R.id.language);
|
||||
mPages = (TextView) mInfo.findViewById(R.id.pages);
|
||||
mSize = (TextView) mInfo.findViewById(R.id.size);
|
||||
mPosted = (TextView) mInfo.findViewById(R.id.posted);
|
||||
mResize = (TextView) mInfo.findViewById(R.id.resize);
|
||||
mFavoredTimes = (TextView) mInfo.findViewById(R.id.favoredTimes);
|
||||
mRatingText = (TextSwitcher) mContent.findViewById(R.id.rating_text);
|
||||
mRating = (RatingView) mContent.findViewById(R.id.rating);
|
||||
mFavorite = (TextView) mContent.findViewById(R.id.favorite);
|
||||
mTorrent = (TextView) mContent.findViewById(R.id.torrent);
|
||||
mShare = (TextView) mContent.findViewById(R.id.share);
|
||||
mRate = (TextView) mContent.findViewById(R.id.rate);
|
||||
mTag = (LinearLayout) mContent.findViewById(R.id.tag);
|
||||
mNoTags = (TextView) mTag.findViewById(no_tags);
|
||||
mComment = (LinearLayout) mContent.findViewById(R.id.comment);
|
||||
mCommentMore = (TextView) mContent.findViewById(R.id.comment_more);
|
||||
mPreviewLayout = (PreviewLayout) mContent.findViewById(R.id.preview);
|
||||
|
||||
mProgressBar = findViewById(R.id.progress_bar);
|
||||
|
||||
mViewTransition = new ViewTransition(mContent, mProgressBar);
|
||||
}
|
||||
|
||||
private void handleAnnouncer(Announcer announcer) {
|
||||
if (announcer == null) {
|
||||
Say.e(TAG, "No announcer in GalleryDetailScene, finish itself");
|
||||
@@ -211,55 +255,23 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener,
|
||||
} else if (ACTION_URL.equals(action)) {
|
||||
|
||||
} else {
|
||||
Say.e(TAG, "Unkonwn action " + action);
|
||||
Say.e(TAG, "GalleryDetailScene: Unkonwn action " + action);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(boolean rebirth) {
|
||||
super.onCreate(rebirth);
|
||||
setContentView(R.layout.scene_gallery_detail);
|
||||
|
||||
mDetailFrameLayout = (FrameLayout) findViewById(R.id.detail_frame_layout);
|
||||
|
||||
mHeader = (ViewGroup) findViewById(R.id.header);
|
||||
mThumb = (LoadImageView) mHeader.findViewById(R.id.thumb);
|
||||
mTitle = (TextView) mHeader.findViewById(R.id.title);
|
||||
mUploader = (TextView) mHeader.findViewById(R.id.uploader);
|
||||
mCategory = (TextView) mHeader.findViewById(R.id.category);
|
||||
|
||||
mActionCard = (ViewGroup) findViewById(R.id.action_card);
|
||||
mRead = mActionCard.findViewById(R.id.read);
|
||||
mDownload = mActionCard.findViewById(R.id.download);
|
||||
|
||||
mContent = (ViewGroup) findViewById(R.id.content);
|
||||
mInfo = (ViewGroup) mContent.findViewById(R.id.info);
|
||||
mLanguage = (TextView) mInfo.findViewById(R.id.language);
|
||||
mPages = (TextView) mInfo.findViewById(R.id.pages);
|
||||
mSize = (TextView) mInfo.findViewById(R.id.size);
|
||||
mPosted = (TextView) mInfo.findViewById(R.id.posted);
|
||||
mResize = (TextView) mInfo.findViewById(R.id.resize);
|
||||
mFavoredTimes = (TextView) mInfo.findViewById(R.id.favoredTimes);
|
||||
mRatingText = (TextSwitcher) mContent.findViewById(R.id.rating_text);
|
||||
mRating = (RatingView) mContent.findViewById(R.id.rating);
|
||||
mFavorite = (TextView) mContent.findViewById(R.id.favorite);
|
||||
mTorrent = (TextView) mContent.findViewById(R.id.torrent);
|
||||
mShare = (TextView) mContent.findViewById(R.id.share);
|
||||
mRate = (TextView) mContent.findViewById(R.id.rate);
|
||||
mTag = (LinearLayout) mContent.findViewById(R.id.tag);
|
||||
mNoTags = (TextView) mTag.findViewById(no_tags);
|
||||
mComment = (LinearLayout) mContent.findViewById(R.id.comment);
|
||||
mCommentMore = (TextView) mContent.findViewById(R.id.comment_more);
|
||||
mPreviewLayout = (PreviewLayout) mContent.findViewById(R.id.preview);
|
||||
|
||||
mProgressBar = findViewById(R.id.progress_bar);
|
||||
|
||||
mViewTransition = new ViewTransition(mContent, mProgressBar);
|
||||
protected void onBind() {
|
||||
super.onBind();
|
||||
|
||||
handleAnnouncer(getAnnouncer());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestore() {
|
||||
super.onRestore();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onGetFitPaddingBottom(int b) {
|
||||
mDetailFrameLayout.setPadding(0, 0, 0, b);
|
||||
@@ -305,14 +317,16 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener,
|
||||
Announcer announcer = new Announcer();
|
||||
announcer.putExtra(InfoScene.KEY_INFO, mGalleryDetail);
|
||||
startScene(InfoScene.class, announcer,
|
||||
new RippleCurtain((int) x + position[0], (int) y + position[1]));
|
||||
new UnionCurtain(new RippleCurtain((int) x + position[0], (int) y + position[1]),
|
||||
new OffsetCurtain(OffsetCurtain.DIRECTION_BOTTOM)));
|
||||
} else if (v == mComment) {
|
||||
int[] position = new int[2];
|
||||
ViewUtils.getLocationInAncestor(mComment, position, getSceneView());
|
||||
Announcer announcer = new Announcer();
|
||||
announcer.putExtra(CommentScene.KEY_COMMENTS, mGalleryDetail.comments);
|
||||
startScene(CommentScene.class, announcer,
|
||||
new RippleCurtain((int) x + position[0], (int) y + position[1]));
|
||||
new UnionCurtain(new RippleCurtain((int) x + position[0], (int) y + position[1]),
|
||||
new OffsetCurtain(OffsetCurtain.DIRECTION_BOTTOM)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ import com.hippo.scene.Announcer;
|
||||
import com.hippo.scene.Curtain;
|
||||
import com.hippo.scene.Scene;
|
||||
import com.hippo.scene.SimpleDialog;
|
||||
import com.hippo.scene.TransitionCurtain;
|
||||
import com.hippo.scene.ElementsSharedCurtain;
|
||||
import com.hippo.util.AnimationUtils;
|
||||
import com.hippo.widget.FabLayout;
|
||||
import com.hippo.widget.FloatingActionButton;
|
||||
@@ -752,7 +752,7 @@ public final class GalleryListScene extends Scene implements SearchBar.Helper,
|
||||
announcer.setAction(GalleryDetailScene.ACTION_GALLERY_INFO);
|
||||
announcer.putExtra(GalleryDetailScene.KEY_GALLERY_INFO, gi);
|
||||
|
||||
Curtain curtain = new TransitionCurtain(new TransitonHelper(position));
|
||||
Curtain curtain = new ElementsSharedCurtain(new TransitonHelper(position));
|
||||
|
||||
startScene(GalleryDetailScene.class, announcer, curtain);
|
||||
|
||||
@@ -766,7 +766,7 @@ public final class GalleryListScene extends Scene implements SearchBar.Helper,
|
||||
}
|
||||
}
|
||||
|
||||
private class TransitonHelper implements TransitionCurtain.ViewPairSet {
|
||||
private class TransitonHelper implements ElementsSharedCurtain.ViewPairSet {
|
||||
|
||||
private int mPosition;
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ public class DownloadSettingsScene extends PreferenceScene implements Preference
|
||||
private static final String KEY_IMAGE_DOWNLOAD_LOACTION = "image_download_location";
|
||||
private static final String KEY_ARCHIVE_DOWNLOAD_LOACTION = "archive_download_location";
|
||||
|
||||
private static Preference mImagePreference;
|
||||
private static Preference mArchivePreference;
|
||||
private Preference mImagePreference;
|
||||
private Preference mArchivePreference;
|
||||
|
||||
@Override
|
||||
protected void onCreate(boolean rebirth) {
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.client.EhConfig;
|
||||
import com.hippo.ehviewer.util.Settings;
|
||||
import com.hippo.scene.SimpleCurtain;
|
||||
import com.hippo.scene.preference.ListPreference;
|
||||
import com.hippo.scene.preference.Preference;
|
||||
import com.hippo.scene.preference.PreferenceCategory;
|
||||
@@ -103,7 +102,7 @@ public final class EHSettingsScene extends PreferenceScene implements Preference
|
||||
public boolean onClick(Preference preference) {
|
||||
String key = preference.getKey();
|
||||
if (Settings.KEY_EXCLUDED_LANGUAGES.equals(key)) {
|
||||
startScene(ExcludedLanguagesScene.class, null, new SimpleCurtain(SimpleCurtain.DIRECTION_BOTTOM));
|
||||
startScene(ExcludedLanguagesScene.class);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -242,7 +242,7 @@ public final class Settings {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return dir != null ? dir : UniFile.fromFile(AppConfig.getDownloadDir());
|
||||
return dir != null ? dir : UniFile.fromFile(AppConfig.getArchiveDir());
|
||||
}
|
||||
|
||||
public static void putArchiveDownloadLocation(UniFile location) {
|
||||
|
||||
@@ -23,7 +23,7 @@ public abstract class Curtain {
|
||||
|
||||
private int mPreviousSceneId;
|
||||
|
||||
void setPreviousScene(@Nullable Scene pScene) {
|
||||
protected void setPreviousScene(@Nullable Scene pScene) {
|
||||
if (pScene == null) {
|
||||
mPreviousSceneId = -1;
|
||||
} else {
|
||||
@@ -31,17 +31,20 @@ public abstract class Curtain {
|
||||
}
|
||||
}
|
||||
|
||||
boolean isPreviousScene(@Nullable Scene scene) {
|
||||
protected boolean isPreviousScene(@Nullable Scene scene) {
|
||||
return scene != null && scene.getId() == mPreviousSceneId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if can NOT still run when previous scene changed
|
||||
*/
|
||||
protected boolean specifyPreviousScene() {
|
||||
protected boolean needSpecifyPreviousScene() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scene rebirth
|
||||
*/
|
||||
protected void onRebirth() {
|
||||
}
|
||||
|
||||
@@ -72,12 +75,4 @@ public abstract class Curtain {
|
||||
protected void dispatchCloseFinished(@NonNull Scene enter, @NonNull Scene exit) {
|
||||
exit.closeFinished();
|
||||
}
|
||||
|
||||
protected void hideSceneOnOpen(@NonNull Scene exit) {
|
||||
exit.setHide(true);
|
||||
}
|
||||
|
||||
protected void showSceneOnClose(@NonNull Scene enter) {
|
||||
enter.setHide(false);
|
||||
}
|
||||
}
|
||||
+160
-175
@@ -31,16 +31,15 @@ import com.hippo.animation.ArgbEvaluator;
|
||||
import com.hippo.animation.SimpleAnimatorListener;
|
||||
import com.hippo.util.AnimationUtils;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
import com.hippo.widget.GlobalLayoutSet;
|
||||
import com.hippo.yorozuya.Say;
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class TransitionCurtain extends Curtain {
|
||||
public class ElementsSharedCurtain extends Curtain {
|
||||
|
||||
private static final String TAG = TransitionCurtain.class.getSimpleName();
|
||||
private static final String TAG = ElementsSharedCurtain.class.getSimpleName();
|
||||
|
||||
private static long ANIMATE_TIME = 300L;
|
||||
|
||||
@@ -48,16 +47,27 @@ public class TransitionCurtain extends Curtain {
|
||||
|
||||
private AnimatorSet mAnimatorSet;
|
||||
|
||||
public TransitionCurtain(ViewPairSet viewPairSet) {
|
||||
public ElementsSharedCurtain(ViewPairSet viewPairSet) {
|
||||
mViewPairSet = viewPairSet;
|
||||
}
|
||||
|
||||
// TODO what if back key press before move animator start
|
||||
|
||||
// Make background from transport to default.
|
||||
// Invisible other
|
||||
@Override
|
||||
public void open(final @NonNull Scene enter, final @NonNull Scene exit) {
|
||||
// Check enter content view
|
||||
View sceneContentView = enter.getSceneView().getChildAt(0);
|
||||
if (sceneContentView == null) {
|
||||
Say.w(TAG, "Can't get enter scene content view");
|
||||
dispatchOpenFinished(enter, exit);
|
||||
return;
|
||||
}
|
||||
// Check stage layout isLayoutRequested
|
||||
final StageLayout stageLayout = enter.getStageLayout();
|
||||
if (!stageLayout.isLayoutRequested()) {
|
||||
Say.w(TAG, "WTF? stageLayout.isLayoutRequested() == false");
|
||||
dispatchOpenFinished(enter, exit);
|
||||
return;
|
||||
}
|
||||
|
||||
final Set<Animator> animatorCollection = new HashSet<>();
|
||||
|
||||
@@ -65,23 +75,17 @@ public class TransitionCurtain extends Curtain {
|
||||
int bgColor = enter.getBackgroundColor();
|
||||
int startBgColor = bgColor & 0xffffff;
|
||||
enter.setBackgroundColor(startBgColor);
|
||||
ObjectAnimator colorAnim = ObjectAnimator.ofInt(enter, "backgroundColor", bgColor);
|
||||
ObjectAnimator colorAnim = ObjectAnimator.ofInt(enter, "backgroundColor", startBgColor, bgColor);
|
||||
colorAnim.setEvaluator(ArgbEvaluator.getInstance());
|
||||
colorAnim.setDuration(ANIMATE_TIME);
|
||||
animatorCollection.add(colorAnim);
|
||||
|
||||
View sceneContentView = enter.getSceneView().getChildAt(0);
|
||||
if (sceneContentView != null) {
|
||||
sceneContentView.setAlpha(0f);
|
||||
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(sceneContentView, "alpha", 0f, 1f);
|
||||
alphaAnim.setDuration(ANIMATE_TIME);
|
||||
animatorCollection.add(alphaAnim);
|
||||
} else {
|
||||
Say.w(TAG, "Can't get enter scene content view");
|
||||
}
|
||||
sceneContentView.setAlpha(0f);
|
||||
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(sceneContentView, "alpha", 0f, 1f);
|
||||
alphaAnim.setDuration(ANIMATE_TIME);
|
||||
animatorCollection.add(alphaAnim);
|
||||
|
||||
GlobalLayoutSet globalLayoutSet = new GlobalLayoutSet();
|
||||
Set<TransitionItem> transitionItemSet = new HashSet<>();
|
||||
final Set<TransitionItem> transitionItemSet = new HashSet<>();
|
||||
|
||||
// Handle transit part
|
||||
View[] enterViews = mViewPairSet.getToViewSet(enter);
|
||||
@@ -108,131 +112,119 @@ public class TransitionCurtain extends Curtain {
|
||||
item.enterView = enterView;
|
||||
item.exitView = exitView;
|
||||
transitionItemSet.add(item);
|
||||
|
||||
globalLayoutSet.addListenerToObserver(enterView.getViewTreeObserver());
|
||||
}
|
||||
|
||||
if (globalLayoutSet.getSize() == 0) {
|
||||
// Not transition view, do animation now
|
||||
new OpenSecondAllLayoutListener(enter, exit, transitionItemSet, animatorCollection).onAllLayout();
|
||||
if (transitionItemSet.isEmpty()) {
|
||||
stageLayout.addOnLayoutListener(new OpenSecondLayoutListener(enter, exit, transitionItemSet, animatorCollection));
|
||||
} else {
|
||||
globalLayoutSet.setOnAllLayoutListener(new OpenFirstAllLayoutListener(
|
||||
enter, exit, transitionItemSet, animatorCollection));
|
||||
stageLayout.addOnLayoutListener(new OpenFirstLayoutListener(enter, exit, transitionItemSet, animatorCollection));
|
||||
}
|
||||
}
|
||||
|
||||
private class OpenFirstAllLayoutListener implements GlobalLayoutSet.OnAllLayoutListener{
|
||||
private class OpenFirstLayoutListener implements StageLayout.OnLayoutListener {
|
||||
|
||||
Scene mEnterScene;
|
||||
Scene mExitScene;
|
||||
Set<TransitionItem> mTransitionItemSet;
|
||||
Set<Animator> mAnimatorCollection;
|
||||
private Scene mEnter;
|
||||
private Scene mExit;
|
||||
private SceneView mEnterView;
|
||||
private SceneView mExitView;
|
||||
private StageLayout mStageLayout;
|
||||
private Set<TransitionItem> mTransitionItems;
|
||||
private Set<Animator> mAnimatorCollection;
|
||||
|
||||
public OpenFirstAllLayoutListener(Scene enterScene, Scene exitScene,
|
||||
Set<TransitionItem> transitionItemSet, Set<Animator> animatorCollection) {
|
||||
mEnterScene = enterScene;
|
||||
mExitScene = exitScene;
|
||||
mTransitionItemSet = transitionItemSet;
|
||||
public OpenFirstLayoutListener(Scene enter, Scene exit, Set<TransitionItem> transitionItems,
|
||||
Set<Animator> animatorCollection) {
|
||||
mEnter = enter;
|
||||
mExit = exit;
|
||||
mEnterView = enter.getSceneView();
|
||||
mExitView = exit.getSceneView();
|
||||
mStageLayout = enter.getStageLayout();
|
||||
mTransitionItems = transitionItems;
|
||||
mAnimatorCollection = animatorCollection;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onAllLayout() {
|
||||
Set<TransitionItem> transitionItemSet = mTransitionItemSet;
|
||||
public void onLayout(View view) {
|
||||
mStageLayout.removeOnLayoutListener(this);
|
||||
|
||||
ViewGroup enterSceneView = mEnterScene.getSceneView();
|
||||
GlobalLayoutSet globalLayoutSet = new GlobalLayoutSet();
|
||||
|
||||
for (TransitionItem item : transitionItemSet) {
|
||||
int[] startloaction = new int[2];
|
||||
int[] endloaction = new int[2];
|
||||
for (TransitionItem item : mTransitionItems) {
|
||||
final View enterView = item.enterView;
|
||||
final View exitView = item.exitView;
|
||||
|
||||
int[] startloaction = new int[2];
|
||||
ViewUtils.getLocationInAncestor(exitView, startloaction, mExitScene.getSceneView());
|
||||
int[] endloaction = new int[2];
|
||||
ViewUtils.getLocationInAncestor(enterView, endloaction, mEnterScene.getSceneView());
|
||||
ViewUtils.getLocationInAncestor(exitView, startloaction, mExitView);
|
||||
ViewUtils.getLocationInAncestor(enterView, endloaction, mEnterView);
|
||||
int startWidth = exitView.getWidth();
|
||||
int startHeight = exitView.getHeight();
|
||||
item.endWidth = enterView.getWidth();
|
||||
item.endHeight = enterView.getHeight();
|
||||
item.startWidth = startWidth;
|
||||
item.startHeight = startHeight;
|
||||
item.endloaction = endloaction;
|
||||
|
||||
// Create bitmap view
|
||||
Bitmap bmp = ViewUtils.getBitmapFromView(enterView);
|
||||
View bmpView = new View(enterView.getContext());
|
||||
item.bmp = bmp;
|
||||
item.bmpView = bmpView;
|
||||
|
||||
bmpView.setBackgroundDrawable(new BitmapDrawable(bmp));
|
||||
bmpView.setBackgroundDrawable(new BitmapDrawable(enterView.getContext().getResources(), bmp));
|
||||
AbsoluteLayout.LayoutParams lp = new AbsoluteLayout.LayoutParams(
|
||||
startWidth, startHeight, startloaction[0], startloaction[1]);
|
||||
enterSceneView.addView(bmpView, lp);
|
||||
mEnterView.addView(bmpView, lp);
|
||||
|
||||
bmpView.setVisibility(View.INVISIBLE);
|
||||
|
||||
globalLayoutSet.addListenerToObserver(bmpView.getViewTreeObserver());
|
||||
bmpView.setPivotX(0);
|
||||
bmpView.setPivotY(0);
|
||||
|
||||
PropertyValuesHolder scaleXPvh = PropertyValuesHolder.ofFloat("scaleX", 1f, (float) enterView.getWidth() / startWidth);
|
||||
PropertyValuesHolder scaleYPvh = PropertyValuesHolder.ofFloat("scaleY", 1f, (float) enterView.getHeight() / startHeight);
|
||||
PropertyValuesHolder xPvh = PropertyValuesHolder.ofFloat("x", startloaction[0], endloaction[0]);
|
||||
PropertyValuesHolder yPvh = PropertyValuesHolder.ofFloat("y", startloaction[1], endloaction[1]);
|
||||
ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(bmpView, scaleXPvh, scaleYPvh, xPvh, yPvh);
|
||||
anim.setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR);
|
||||
anim.setDuration(ANIMATE_TIME);
|
||||
|
||||
mAnimatorCollection.add(anim);
|
||||
}
|
||||
|
||||
globalLayoutSet.setOnAllLayoutListener(new OpenSecondAllLayoutListener(
|
||||
mEnterScene, mExitScene, transitionItemSet, mAnimatorCollection));
|
||||
mStageLayout.addOnLayoutListener(new OpenSecondLayoutListener(mEnter, mExit, mTransitionItems, mAnimatorCollection));
|
||||
}
|
||||
}
|
||||
|
||||
private class OpenSecondAllLayoutListener implements GlobalLayoutSet.OnAllLayoutListener{
|
||||
private class OpenSecondLayoutListener implements StageLayout.OnLayoutListener {
|
||||
|
||||
Scene mEnterScene;
|
||||
Scene mExitScene;
|
||||
Set<TransitionItem> mTransitionItemSet;
|
||||
Set<Animator> mAnimatorCollection;
|
||||
private Scene mEnter;
|
||||
private Scene mExit;
|
||||
private Set<TransitionItem> mTransitionItems;
|
||||
private Set<Animator> mAnimatorCollection;
|
||||
|
||||
public OpenSecondAllLayoutListener(Scene enterScene, Scene exitScene,
|
||||
Set<TransitionItem> transitionItemSet, Set<Animator> animatorCollection) {
|
||||
mEnterScene = enterScene;
|
||||
mExitScene = exitScene;
|
||||
mTransitionItemSet = transitionItemSet;
|
||||
public OpenSecondLayoutListener(Scene enter, Scene exit, Set<TransitionItem> transitionItems,
|
||||
Set<Animator> animatorCollection) {
|
||||
mEnter = enter;
|
||||
mExit = exit;
|
||||
mTransitionItems = transitionItems;
|
||||
mAnimatorCollection = animatorCollection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAllLayout() {
|
||||
Set<TransitionItem> transitionItemSet = mTransitionItemSet;
|
||||
Set<Animator> animatorCollection = mAnimatorCollection;
|
||||
public void onLayout(View view) {
|
||||
mEnter.getStageLayout().removeOnLayoutListener(this);
|
||||
|
||||
for (TransitionItem item : transitionItemSet) {
|
||||
for (TransitionItem item : mTransitionItems) {
|
||||
View exitView = item.exitView;
|
||||
View bmpView = item.bmpView;
|
||||
|
||||
exitView.setVisibility(View.INVISIBLE);
|
||||
bmpView.setVisibility(View.VISIBLE);
|
||||
|
||||
bmpView.setPivotX(0);
|
||||
bmpView.setPivotY(0);
|
||||
|
||||
PropertyValuesHolder scaleXPvh = PropertyValuesHolder.ofFloat("scaleX", (float) item.endWidth / item.startWidth);
|
||||
PropertyValuesHolder scaleYPvh = PropertyValuesHolder.ofFloat("scaleY", (float) item.endHeight/ item.startHeight);
|
||||
PropertyValuesHolder xPvh = PropertyValuesHolder.ofFloat("x", item.endloaction[0]);
|
||||
PropertyValuesHolder yPvh = PropertyValuesHolder.ofFloat("y", item.endloaction[1]);
|
||||
ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(bmpView, scaleXPvh, scaleYPvh, xPvh, yPvh);
|
||||
anim.setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR);
|
||||
anim.setDuration(ANIMATE_TIME);
|
||||
|
||||
animatorCollection.add(anim);
|
||||
}
|
||||
|
||||
mAnimatorSet = new AnimatorSet();
|
||||
mAnimatorSet.playTogether(animatorCollection);
|
||||
mAnimatorSet.playTogether(mAnimatorCollection);
|
||||
mAnimatorSet.addListener(new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
dispatchOpenFinished(mEnterScene, mExitScene);
|
||||
hideSceneOnOpen(mExitScene);
|
||||
for (TransitionItem item : mTransitionItemSet) {
|
||||
dispatchOpenFinished(mEnter, mExit);
|
||||
ViewGroup enterSceneView = mEnter.getSceneView();
|
||||
for (TransitionItem item : mTransitionItems) {
|
||||
item.enterView.setVisibility(View.VISIBLE);
|
||||
item.exitView.setVisibility(View.VISIBLE);
|
||||
|
||||
ViewGroup enterSceneView = mEnterScene.getSceneView();
|
||||
enterSceneView.removeView(item.bmpView);
|
||||
|
||||
item.bmp.recycle();
|
||||
@@ -244,31 +236,30 @@ public class TransitionCurtain extends Curtain {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close(final @NonNull Scene enter, final @NonNull Scene exit) {
|
||||
showSceneOnClose(enter);
|
||||
// Check enter content view
|
||||
View sceneContentView = exit.getSceneView().getChildAt(0);
|
||||
if (sceneContentView == null) {
|
||||
Say.w(TAG, "Can't get exit scene content view");
|
||||
dispatchOpenFinished(enter, exit);
|
||||
return;
|
||||
}
|
||||
|
||||
final Set<Animator> animatorCollection = new HashSet<>();
|
||||
|
||||
// Handle background
|
||||
int bgColor = exit.getBackgroundColor();
|
||||
int endBgColor = bgColor & 0xffffff;
|
||||
ObjectAnimator colorAnim = ObjectAnimator.ofInt(exit, "backgroundColor", endBgColor);
|
||||
ObjectAnimator colorAnim = ObjectAnimator.ofInt(exit, "backgroundColor", bgColor, endBgColor);
|
||||
colorAnim.setEvaluator(ArgbEvaluator.getInstance());
|
||||
colorAnim.setDuration(ANIMATE_TIME);
|
||||
animatorCollection.add(colorAnim);
|
||||
|
||||
View sceneContentView = exit.getSceneView().getChildAt(0);
|
||||
if (sceneContentView != null) {
|
||||
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(sceneContentView, "alpha", 0f);
|
||||
alphaAnim.setDuration(ANIMATE_TIME);
|
||||
animatorCollection.add(alphaAnim);
|
||||
} else {
|
||||
Say.w(TAG, "Can't get enter scene content view");
|
||||
}
|
||||
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(sceneContentView, "alpha", 1f, 0f);
|
||||
alphaAnim.setDuration(ANIMATE_TIME);
|
||||
animatorCollection.add(alphaAnim);
|
||||
|
||||
GlobalLayoutSet globalLayoutSet = new GlobalLayoutSet();
|
||||
Set<TransitionItem> transitionItemSet = new HashSet<>();
|
||||
|
||||
// Handle transit part
|
||||
@@ -296,56 +287,59 @@ public class TransitionCurtain extends Curtain {
|
||||
item.enterView = enterView;
|
||||
item.exitView = exitView;
|
||||
transitionItemSet.add(item);
|
||||
|
||||
globalLayoutSet.addListenerToObserver(enterView.getViewTreeObserver());
|
||||
}
|
||||
|
||||
if (globalLayoutSet.getSize() == 0) {
|
||||
new CloseSecondAllLayoutListener(enter, exit, transitionItemSet, animatorCollection).onAllLayout();
|
||||
final StageLayout stageLayout = enter.getStageLayout();
|
||||
if (stageLayout.isLayoutRequested()) {
|
||||
if (transitionItemSet.isEmpty()) {
|
||||
stageLayout.addOnLayoutListener(new CloseSecondLayoutListener(enter, exit, transitionItemSet, animatorCollection));
|
||||
} else {
|
||||
stageLayout.addOnLayoutListener(new CloseFirstLayoutListener(enter, exit, transitionItemSet, animatorCollection));
|
||||
}
|
||||
} else {
|
||||
globalLayoutSet.setOnAllLayoutListener(new CloseFirstAllLayoutListener(
|
||||
enter, exit, transitionItemSet, animatorCollection));
|
||||
if (transitionItemSet.isEmpty()) {
|
||||
new CloseSecondLayoutListener(enter, exit, transitionItemSet, animatorCollection).onLayout(stageLayout);
|
||||
} else {
|
||||
new CloseFirstLayoutListener(enter, exit, transitionItemSet, animatorCollection).onLayout(stageLayout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CloseFirstAllLayoutListener implements GlobalLayoutSet.OnAllLayoutListener{
|
||||
private class CloseFirstLayoutListener implements StageLayout.OnLayoutListener {
|
||||
|
||||
Scene mEnterScene;
|
||||
Scene mExitScene;
|
||||
Set<TransitionItem> mTransitionItemSet;
|
||||
Set<Animator> mAnimatorCollection;
|
||||
private Scene mEnter;
|
||||
private Scene mExit;
|
||||
private SceneView mEnterView;
|
||||
private SceneView mExitView;
|
||||
private StageLayout mStageLayout;
|
||||
private Set<TransitionItem> mTransitionItems;
|
||||
private Set<Animator> mAnimatorCollection;
|
||||
|
||||
public CloseFirstAllLayoutListener(Scene enterScene, Scene exitScene,
|
||||
Set<TransitionItem> transitionItemSet, Set<Animator> animatorCollection) {
|
||||
mEnterScene = enterScene;
|
||||
mExitScene = exitScene;
|
||||
mTransitionItemSet = transitionItemSet;
|
||||
public CloseFirstLayoutListener(Scene enter, Scene exit, Set<TransitionItem> transitionItems,
|
||||
Set<Animator> animatorCollection) {
|
||||
mEnter = enter;
|
||||
mExit = exit;
|
||||
mEnterView = enter.getSceneView();
|
||||
mExitView = exit.getSceneView();
|
||||
mStageLayout = enter.getStageLayout();
|
||||
mTransitionItems = transitionItems;
|
||||
mAnimatorCollection = animatorCollection;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onAllLayout() {
|
||||
Set<TransitionItem> transitionItemSet = mTransitionItemSet;
|
||||
public void onLayout(View view) {
|
||||
mStageLayout.removeOnLayoutListener(this);
|
||||
|
||||
ViewGroup exitSceneView = mExitScene.getSceneView();
|
||||
GlobalLayoutSet globalLayoutSet = new GlobalLayoutSet();
|
||||
|
||||
for (TransitionItem item : transitionItemSet) {
|
||||
int[] startloaction = new int[2];
|
||||
int[] endloaction = new int[2];
|
||||
for (TransitionItem item : mTransitionItems) {
|
||||
final View enterView = item.enterView;
|
||||
final View exitView = item.exitView;
|
||||
|
||||
int[] startloaction = new int[2];
|
||||
ViewUtils.getLocationInAncestor(exitView, startloaction, mExitScene.getSceneView());
|
||||
int[] endloaction = new int[2];
|
||||
ViewUtils.getLocationInAncestor(enterView, endloaction, mEnterScene.getSceneView());
|
||||
ViewUtils.getLocationInAncestor(exitView, startloaction, mExitView);
|
||||
ViewUtils.getLocationInAncestor(enterView, endloaction, mEnterView);
|
||||
int startWidth = exitView.getWidth();
|
||||
int startHeight = exitView.getHeight();
|
||||
item.endWidth = enterView.getWidth();
|
||||
item.endHeight = enterView.getHeight();
|
||||
item.startWidth = startWidth;
|
||||
item.startHeight = startHeight;
|
||||
item.endloaction = endloaction;
|
||||
|
||||
Bitmap bmp = ViewUtils.getBitmapFromView(enterView);
|
||||
View bmpView = new View(exitView.getContext());
|
||||
@@ -355,70 +349,66 @@ public class TransitionCurtain extends Curtain {
|
||||
bmpView.setBackgroundDrawable(new BitmapDrawable(bmp));
|
||||
AbsoluteLayout.LayoutParams lp = new AbsoluteLayout.LayoutParams(
|
||||
startWidth, startHeight, startloaction[0], startloaction[1]);
|
||||
exitSceneView.addView(bmpView, lp);
|
||||
mExitView.addView(bmpView, lp);
|
||||
|
||||
bmpView.setVisibility(View.INVISIBLE);
|
||||
|
||||
globalLayoutSet.addListenerToObserver(bmpView.getViewTreeObserver());
|
||||
bmpView.setPivotX(0);
|
||||
bmpView.setPivotY(0);
|
||||
|
||||
PropertyValuesHolder scaleXPvh = PropertyValuesHolder.ofFloat("scaleX", 1f, (float) enterView.getWidth() / startWidth);
|
||||
PropertyValuesHolder scaleYPvh = PropertyValuesHolder.ofFloat("scaleY", 1f, (float) enterView.getHeight() / startHeight);
|
||||
PropertyValuesHolder xPvh = PropertyValuesHolder.ofFloat("x", startloaction[0], endloaction[0]);
|
||||
PropertyValuesHolder yPvh = PropertyValuesHolder.ofFloat("y", startloaction[1], endloaction[1]);
|
||||
ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(bmpView, scaleXPvh, scaleYPvh, xPvh, yPvh);
|
||||
anim.setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR);
|
||||
anim.setDuration(ANIMATE_TIME);
|
||||
|
||||
mAnimatorCollection.add(anim);
|
||||
}
|
||||
|
||||
globalLayoutSet.setOnAllLayoutListener(new CloseSecondAllLayoutListener(
|
||||
mEnterScene, mExitScene, transitionItemSet, mAnimatorCollection));
|
||||
mStageLayout.addOnLayoutListener(new CloseSecondLayoutListener(mEnter, mExit, mTransitionItems, mAnimatorCollection));
|
||||
}
|
||||
}
|
||||
|
||||
private class CloseSecondAllLayoutListener implements GlobalLayoutSet.OnAllLayoutListener{
|
||||
private class CloseSecondLayoutListener implements StageLayout.OnLayoutListener {
|
||||
|
||||
Scene mEnterScene;
|
||||
Scene mExitScene;
|
||||
Set<TransitionItem> mTransitionItemSet;
|
||||
Set<Animator> mAnimatorCollection;
|
||||
private Scene mEnter;
|
||||
private Scene mExit;
|
||||
private Set<TransitionItem> mTransitionItems;
|
||||
private Set<Animator> mAnimatorCollection;
|
||||
|
||||
public CloseSecondAllLayoutListener(Scene enterScene, Scene exitScene,
|
||||
Set<TransitionItem> transitionItemSet, Set<Animator> animatorCollection) {
|
||||
mEnterScene = enterScene;
|
||||
mExitScene = exitScene;
|
||||
mTransitionItemSet = transitionItemSet;
|
||||
public CloseSecondLayoutListener(Scene enter, Scene exit, Set<TransitionItem> transitionItems,
|
||||
Set<Animator> animatorCollection) {
|
||||
mEnter = enter;
|
||||
mExit = exit;
|
||||
mTransitionItems = transitionItems;
|
||||
mAnimatorCollection = animatorCollection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAllLayout() {
|
||||
Set<TransitionItem> transitionItemSet = mTransitionItemSet;
|
||||
Set<Animator> animatorCollection = mAnimatorCollection;
|
||||
public void onLayout(View view) {
|
||||
mEnter.getStageLayout().removeOnLayoutListener(this);
|
||||
|
||||
for (TransitionItem item : transitionItemSet) {
|
||||
for (TransitionItem item : mTransitionItems) {
|
||||
View exitView = item.exitView;
|
||||
View bmpView = item.bmpView;
|
||||
|
||||
exitView.setVisibility(View.INVISIBLE);
|
||||
bmpView.setVisibility(View.VISIBLE);
|
||||
|
||||
bmpView.setPivotX(0);
|
||||
bmpView.setPivotY(0);
|
||||
|
||||
PropertyValuesHolder scaleXPvh = PropertyValuesHolder.ofFloat("scaleX", (float) item.endWidth / item.startWidth);
|
||||
PropertyValuesHolder scaleYPvh = PropertyValuesHolder.ofFloat("scaleY", (float) item.endHeight/ item.startHeight);
|
||||
PropertyValuesHolder xPvh = PropertyValuesHolder.ofFloat("x", item.endloaction[0]);
|
||||
PropertyValuesHolder yPvh = PropertyValuesHolder.ofFloat("y", item.endloaction[1]);
|
||||
ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(bmpView, scaleXPvh, scaleYPvh, xPvh, yPvh);
|
||||
anim.setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR);
|
||||
anim.setDuration(ANIMATE_TIME);
|
||||
|
||||
animatorCollection.add(anim);
|
||||
}
|
||||
|
||||
mAnimatorSet = new AnimatorSet();
|
||||
mAnimatorSet.playTogether(animatorCollection);
|
||||
mAnimatorSet.playTogether(mAnimatorCollection);
|
||||
mAnimatorSet.addListener(new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
dispatchCloseFinished(mEnterScene, mExitScene);
|
||||
for (TransitionItem item : mTransitionItemSet) {
|
||||
dispatchCloseFinished(mEnter, mExit);
|
||||
ViewGroup exitSceneView = mExit.getSceneView();
|
||||
for (TransitionItem item : mTransitionItems) {
|
||||
item.enterView.setVisibility(View.VISIBLE);
|
||||
item.exitView.setVisibility(View.VISIBLE);
|
||||
|
||||
ViewGroup exitSceneView = mExitScene.getSceneView();
|
||||
exitSceneView.removeView(item.bmpView);
|
||||
|
||||
item.bmp.recycle();
|
||||
@@ -447,15 +437,10 @@ public class TransitionCurtain extends Curtain {
|
||||
View exitView;
|
||||
Bitmap bmp;
|
||||
View bmpView;
|
||||
int[] endloaction;
|
||||
int startWidth;
|
||||
int startHeight;
|
||||
int endWidth;
|
||||
int endHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* the interface help {@link TransitionCurtain} to get the views to do transfer
|
||||
* the interface help {@link ElementsSharedCurtain} to get the views to do transfer
|
||||
*/
|
||||
public interface ViewPairSet {
|
||||
View[] getFromViewSet(@NonNull Scene fromScene);
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.scene;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
|
||||
import com.hippo.animation.SimpleAnimatorListener;
|
||||
import com.hippo.util.AnimationUtils;
|
||||
import com.hippo.yorozuya.Say;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class OffsetCurtain extends Curtain {
|
||||
|
||||
private static final String TAG = OffsetCurtain.class.getSimpleName();
|
||||
|
||||
private static long ANIMATE_TIME = 300L;
|
||||
|
||||
public static final int DIRECTION_LEFT = 0;
|
||||
public static final int DIRECTION_TOP = 1;
|
||||
public static final int DIRECTION_RIGHT = 2;
|
||||
public static final int DIRECTION_BOTTOM = 3;
|
||||
|
||||
private int mDirection;
|
||||
private float mOffsetPercent;
|
||||
|
||||
private AnimatorSet mAnimatorSet;
|
||||
|
||||
public OffsetCurtain(int direction) {
|
||||
this(direction, 0.25f);
|
||||
}
|
||||
|
||||
public OffsetCurtain(int direction, float offsetPercent) {
|
||||
mDirection = direction;
|
||||
mOffsetPercent = offsetPercent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean needSpecifyPreviousScene() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(@NonNull final Scene enter, @NonNull final Scene exit) {
|
||||
// Check stage layout isLayoutRequested
|
||||
final StageLayout stageLayout = enter.getStageLayout();
|
||||
if (!stageLayout.isLayoutRequested()) {
|
||||
Say.w(TAG, "WTF? stageLayout.isLayoutRequested() == false");
|
||||
dispatchOpenFinished(enter, exit);
|
||||
return;
|
||||
}
|
||||
|
||||
final View enterSceneView = enter.getSceneView();
|
||||
enterSceneView.setVisibility(View.INVISIBLE);
|
||||
|
||||
stageLayout.addOnLayoutListener(new StageLayout.OnLayoutListener() {
|
||||
@Override
|
||||
public void onLayout(View view) {
|
||||
stageLayout.removeOnLayoutListener(this);
|
||||
|
||||
final Set<Animator> animatorCollection = new HashSet<>();
|
||||
|
||||
int width = enterSceneView.getWidth();
|
||||
int height = enterSceneView.getHeight();
|
||||
float translationX = 0f;
|
||||
float translationY = 0f;
|
||||
switch (mDirection) {
|
||||
case DIRECTION_LEFT:
|
||||
translationX = -width * mOffsetPercent;
|
||||
break;
|
||||
case DIRECTION_TOP:
|
||||
translationY = -height * mOffsetPercent;
|
||||
break;
|
||||
case DIRECTION_RIGHT:
|
||||
translationX = width * mOffsetPercent;
|
||||
break;
|
||||
default:
|
||||
case DIRECTION_BOTTOM:
|
||||
translationY = height * mOffsetPercent;
|
||||
break;
|
||||
}
|
||||
PropertyValuesHolder pvh;
|
||||
if (translationX != 0f) {
|
||||
pvh = PropertyValuesHolder.ofFloat("translationX", translationX, 0f);
|
||||
} else {
|
||||
pvh = PropertyValuesHolder.ofFloat("translationY", translationY, 0f);
|
||||
}
|
||||
Animator offsetAnimator = ObjectAnimator.ofPropertyValuesHolder(enterSceneView, pvh);
|
||||
offsetAnimator.setDuration(ANIMATE_TIME);
|
||||
offsetAnimator.setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR);
|
||||
animatorCollection.add(offsetAnimator);
|
||||
|
||||
View enterView = enter.getSceneView();
|
||||
enterView.setAlpha(0f);
|
||||
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(enterView, "alpha", 0f, 1f);
|
||||
alphaAnim.setDuration(ANIMATE_TIME);
|
||||
alphaAnim.setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR);
|
||||
animatorCollection.add(alphaAnim);
|
||||
|
||||
mAnimatorSet = new AnimatorSet();
|
||||
mAnimatorSet.playTogether(animatorCollection);
|
||||
mAnimatorSet.addListener(new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
enterSceneView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
dispatchOpenFinished(enter, exit);
|
||||
mAnimatorSet = null;
|
||||
}
|
||||
});
|
||||
mAnimatorSet.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(@NonNull final Scene enter, @NonNull final Scene exit) {
|
||||
// Check stage layout isLayoutRequested
|
||||
final StageLayout stageLayout = enter.getStageLayout();
|
||||
if (stageLayout.isLayoutRequested()) {
|
||||
stageLayout.addOnLayoutListener(new StageLayout.OnLayoutListener() {
|
||||
@Override
|
||||
public void onLayout(View view) {
|
||||
stageLayout.removeOnLayoutListener(this);
|
||||
onClose(enter, exit);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
onClose(enter, exit);
|
||||
}
|
||||
}
|
||||
|
||||
private void onClose(final Scene enter, final Scene exit) {
|
||||
final Set<Animator> animatorCollection = new HashSet<>();
|
||||
|
||||
final View exitSceneView = exit.getSceneView();
|
||||
int width = exitSceneView.getWidth();
|
||||
int height = exitSceneView.getHeight();
|
||||
float translationX = 0f;
|
||||
float translationY = 0f;
|
||||
switch (mDirection) {
|
||||
case DIRECTION_LEFT:
|
||||
translationX = -width * mOffsetPercent;
|
||||
break;
|
||||
case DIRECTION_TOP:
|
||||
translationY = -height * mOffsetPercent;
|
||||
break;
|
||||
case DIRECTION_RIGHT:
|
||||
translationX = width * mOffsetPercent;
|
||||
break;
|
||||
default:
|
||||
case DIRECTION_BOTTOM:
|
||||
translationY = height * mOffsetPercent;
|
||||
break;
|
||||
}
|
||||
PropertyValuesHolder pvh;
|
||||
if (translationX != 0f) {
|
||||
pvh = PropertyValuesHolder.ofFloat("translationX", 0f, translationX);
|
||||
} else {
|
||||
pvh = PropertyValuesHolder.ofFloat("translationY", 0f, translationY);
|
||||
}
|
||||
Animator offsetAnimator = ObjectAnimator.ofPropertyValuesHolder(exitSceneView, pvh);
|
||||
offsetAnimator.setDuration(ANIMATE_TIME);
|
||||
offsetAnimator.setInterpolator(AnimationUtils.SLOW_FAST_INTERPOLATOR);
|
||||
animatorCollection.add(offsetAnimator);
|
||||
|
||||
View exitView = exit.getSceneView();
|
||||
exitView.setAlpha(1f);
|
||||
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(exitView, "alpha", 1f, 0f);
|
||||
alphaAnim.setDuration(ANIMATE_TIME);
|
||||
alphaAnim.setInterpolator(AnimationUtils.SLOW_FAST_INTERPOLATOR);
|
||||
animatorCollection.add(alphaAnim);
|
||||
|
||||
mAnimatorSet = new AnimatorSet();
|
||||
mAnimatorSet.playTogether(animatorCollection);
|
||||
mAnimatorSet.addListener(new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
dispatchCloseFinished(enter, exit);
|
||||
mAnimatorSet = null;
|
||||
}
|
||||
});
|
||||
mAnimatorSet.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endAnimation() {
|
||||
if (mAnimatorSet != null) {
|
||||
mAnimatorSet.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInAnimation() {
|
||||
return mAnimatorSet != null;
|
||||
}
|
||||
}
|
||||
@@ -6,12 +6,10 @@ import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import com.hippo.animation.DurationInterpolator;
|
||||
import com.hippo.animation.SimpleAnimatorListener;
|
||||
import com.hippo.yorozuya.Say;
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -33,6 +31,11 @@ public class RippleCurtain extends Curtain {
|
||||
mStartY = startY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean needSpecifyPreviousScene() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRebirth() {
|
||||
mStartX = 0;
|
||||
@@ -41,16 +44,24 @@ public class RippleCurtain extends Curtain {
|
||||
|
||||
@Override
|
||||
public void open(@NonNull final Scene enter, @NonNull final Scene exit) {
|
||||
// Check stage layout isLayoutRequested
|
||||
final StageLayout stageLayout = enter.getStageLayout();
|
||||
if (!stageLayout.isLayoutRequested()) {
|
||||
Say.w(TAG, "WTF? stageLayout.isLayoutRequested() == false");
|
||||
dispatchOpenFinished(enter, exit);
|
||||
return;
|
||||
}
|
||||
|
||||
final Set<Animator> animatorCollection = new HashSet<>();
|
||||
|
||||
final SceneView enterView = enter.getSceneView();
|
||||
enterView.setStartPoint(mStartX, mStartY);
|
||||
enterView.setVisibility(View.INVISIBLE);
|
||||
|
||||
enterView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
stageLayout.addOnLayoutListener(new StageLayout.OnLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
ViewUtils.removeOnGlobalLayoutListener(enterView.getViewTreeObserver(), this);
|
||||
public void onLayout(View view) {
|
||||
stageLayout.removeOnLayoutListener(this);
|
||||
|
||||
final View sceneContentView = enter.getSceneView().getChildAt(0);
|
||||
if (sceneContentView != null) {
|
||||
@@ -85,7 +96,6 @@ public class RippleCurtain extends Curtain {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
dispatchOpenFinished(enter, exit);
|
||||
hideSceneOnOpen(exit);
|
||||
mAnimatorSet = null;
|
||||
}
|
||||
});
|
||||
@@ -96,8 +106,22 @@ public class RippleCurtain extends Curtain {
|
||||
|
||||
@Override
|
||||
public void close(@NonNull final Scene enter, @NonNull final Scene exit) {
|
||||
showSceneOnClose(enter);
|
||||
// Check stage layout isLayoutRequested
|
||||
final StageLayout stageLayout = enter.getStageLayout();
|
||||
if (stageLayout.isLayoutRequested()) {
|
||||
stageLayout.addOnLayoutListener(new StageLayout.OnLayoutListener() {
|
||||
@Override
|
||||
public void onLayout(View view) {
|
||||
stageLayout.removeOnLayoutListener(this);
|
||||
onClose(enter, exit);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
onClose(enter, exit);
|
||||
}
|
||||
}
|
||||
|
||||
private void onClose(final Scene enter, final Scene exit) {
|
||||
final Set<Animator> animatorCollection = new HashSet<>();
|
||||
|
||||
final SceneView exitView = exit.getSceneView();
|
||||
|
||||
@@ -26,12 +26,10 @@ import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
/**
|
||||
* {@link com.hippo.scene.Scene} is a {@code Activity} of {@link android.app.Activity}.
|
||||
@@ -68,7 +66,7 @@ public abstract class Scene {
|
||||
|
||||
private int mId;
|
||||
|
||||
private boolean mHide;
|
||||
private boolean mHide = false;
|
||||
|
||||
public void setSceneManager(SceneManager sceneManager) {
|
||||
mSceneManager = sceneManager;
|
||||
@@ -123,16 +121,20 @@ public abstract class Scene {
|
||||
}
|
||||
|
||||
public void startScene(@NonNull Class sceneClass) {
|
||||
mSceneManager.startScene(sceneClass, null, null);
|
||||
startScene(sceneClass, null, null);
|
||||
}
|
||||
|
||||
public void startScene(@NonNull Class sceneClass, @Nullable Announcer announcer) {
|
||||
mSceneManager.startScene(sceneClass, announcer, null);
|
||||
startScene(sceneClass, announcer, null);
|
||||
}
|
||||
|
||||
public Curtain getDefaultCurtain() {
|
||||
return new OffsetCurtain(OffsetCurtain.DIRECTION_BOTTOM);
|
||||
}
|
||||
|
||||
public void startScene(@NonNull Class sceneClass, @Nullable Announcer announcer,
|
||||
@Nullable Curtain curtain) {
|
||||
mSceneManager.startScene(sceneClass, announcer, curtain);
|
||||
mSceneManager.startScene(sceneClass, announcer, curtain == null ? getDefaultCurtain() : curtain);
|
||||
}
|
||||
|
||||
int getState() {
|
||||
@@ -148,20 +150,33 @@ public abstract class Scene {
|
||||
}
|
||||
|
||||
public final void finish() {
|
||||
mSceneManager.finishScene(this);
|
||||
mSceneManager.finishScene(this, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell {@link SceneManager} how to {@link View#setVisibility(int)} when it is not the first scene.
|
||||
* If it covers previous scene completely, {@link SceneManager} will setVisibility(View.INVISIBLE),
|
||||
* otherwise setVisibility(View.VISIBLE)
|
||||
*
|
||||
* @return {@code true} if it covers previous scene completely
|
||||
*/
|
||||
protected boolean coverCompletely() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void setHide(boolean hide) {
|
||||
checkSceneView();
|
||||
mHide = hide;
|
||||
if (hide) {
|
||||
mSceneView.setVisibility(View.GONE);
|
||||
} else {
|
||||
mSceneView.setVisibility(View.VISIBLE);
|
||||
if (mHide != hide) {
|
||||
mHide = hide;
|
||||
if (hide) {
|
||||
mSceneView.setVisibility(View.INVISIBLE);
|
||||
} else {
|
||||
mSceneView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean getHide() {
|
||||
boolean isHide() {
|
||||
return mHide;
|
||||
}
|
||||
|
||||
@@ -197,13 +212,8 @@ public abstract class Scene {
|
||||
// Hide it if it is hidden
|
||||
if (mHide) {
|
||||
mSceneView.setVisibility(View.INVISIBLE);
|
||||
mSceneView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
ViewUtils.removeOnGlobalLayoutListener(mSceneView.getViewTreeObserver(), this);
|
||||
mSceneView.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mSceneView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,6 +407,10 @@ public abstract class Scene {
|
||||
}
|
||||
}
|
||||
|
||||
public StageLayout getStageLayout() {
|
||||
return getStageActivity().getStageLayout();
|
||||
}
|
||||
|
||||
// Add scene view to stage layout
|
||||
void attachToStage() {
|
||||
if (mSceneView != null && !isInStage()) {
|
||||
|
||||
@@ -116,10 +116,14 @@ public class SceneManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPrepareToDie(Scene scene) {
|
||||
/// Ture is finishScene is called
|
||||
private boolean checkPrepareToDie(Scene scene) {
|
||||
if (mPrepareToDieSceneSet.contains(scene)) {
|
||||
mPrepareToDieSceneSet.remove(scene);
|
||||
finishScene(scene);
|
||||
finishScene(scene, true);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +179,20 @@ public class SceneManager {
|
||||
startScene(dialog, curtain);
|
||||
}
|
||||
|
||||
private void updateSceneVisibility() {
|
||||
int pointer = mSceneStack.size() - 1;
|
||||
for (; pointer >= 0; pointer--) {
|
||||
Scene scene = mSceneStack.get(pointer);
|
||||
scene.setHide(false);
|
||||
if (scene.coverCompletely()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (pointer--; pointer >= 0; pointer--) {
|
||||
mSceneStack.get(pointer).setHide(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void startScene(Scene scene, Curtain curtain) {
|
||||
Scene previousState = getTopScene();
|
||||
mSceneStack.push(scene);
|
||||
@@ -199,13 +217,18 @@ public class SceneManager {
|
||||
scene.setFitPaddingBottom(fitPaddingBottom);
|
||||
}
|
||||
|
||||
if (curtain != null && previousState != null) {
|
||||
scene.setState(Scene.SCENE_STATE_OPEN);
|
||||
curtain.open(scene, previousState);
|
||||
// Set state run by curtain
|
||||
} else {
|
||||
scene.setState(Scene.SCENE_STATE_RUN);
|
||||
checkPrepareToDie(scene);
|
||||
scene.setState(Scene.SCENE_STATE_RUN);
|
||||
if (!checkPrepareToDie(scene)) {
|
||||
// No finish called. Go on
|
||||
if (curtain != null && previousState != null) {
|
||||
scene.setState(Scene.SCENE_STATE_OPEN);
|
||||
curtain.open(scene, previousState);
|
||||
} else {
|
||||
// No curtain, set visiblity for previousState here
|
||||
if (previousState != null) {
|
||||
updateSceneVisibility();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +251,7 @@ public class SceneManager {
|
||||
}
|
||||
}
|
||||
|
||||
void finishScene(@NonNull Scene scene) {
|
||||
void finishScene(@NonNull Scene scene, boolean noAnimation) {
|
||||
checkLoop();
|
||||
|
||||
int index = getSceneIndex(scene);
|
||||
@@ -248,7 +271,7 @@ public class SceneManager {
|
||||
|
||||
// TODO If the cene is under a dialog, the previous may not show
|
||||
if (index != mSceneStack.size() - 1 || index == 0) {
|
||||
// It is the last scene, just finish the activity
|
||||
// It is not the first or it is the last scene
|
||||
mSceneStack.remove(index);
|
||||
scene.destroy(true);
|
||||
scene.setState(Scene.SCENE_STATE_DESTROY);
|
||||
@@ -256,7 +279,11 @@ public class SceneManager {
|
||||
scene.setState(Scene.SCENE_STATE_DIE);
|
||||
|
||||
if (index == 0) {
|
||||
// It is the last scene, just finish the activity
|
||||
getStageActivity().finish();
|
||||
} else {
|
||||
// Update the scene under target scene visibility
|
||||
updateSceneVisibility();
|
||||
}
|
||||
} else {
|
||||
mSceneStack.remove(index);
|
||||
@@ -267,9 +294,12 @@ public class SceneManager {
|
||||
|
||||
scene.destroy(true);
|
||||
|
||||
// Update scene visibility
|
||||
updateSceneVisibility();
|
||||
|
||||
Curtain curtain = scene.getCurtain();
|
||||
if (curtain != null &&
|
||||
(!curtain.specifyPreviousScene() || curtain.isPreviousScene(previousScene))) {
|
||||
if (!noAnimation && curtain != null &&
|
||||
(!curtain.needSpecifyPreviousScene() || curtain.isPreviousScene(previousScene))) {
|
||||
scene.setState(Scene.SCENE_STATE_CLOSE);
|
||||
curtain.close(previousScene, scene);
|
||||
// add the scene to legacy set
|
||||
@@ -279,6 +309,8 @@ public class SceneManager {
|
||||
scene.setState(Scene.SCENE_STATE_DESTROY);
|
||||
scene.die(false);
|
||||
scene.setState(Scene.SCENE_STATE_DIE);
|
||||
|
||||
previousScene.setHide(false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -296,6 +328,7 @@ public class SceneManager {
|
||||
scene.open();
|
||||
scene.setState(Scene.SCENE_STATE_RUN);
|
||||
checkPrepareToDie(scene);
|
||||
updateSceneVisibility();
|
||||
}
|
||||
|
||||
void closeScene(Scene scene) {
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.scene;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import com.hippo.animation.SimpleAnimatorListener;
|
||||
import com.hippo.util.AnimationUtils;
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
public class SimpleCurtain extends Curtain {
|
||||
|
||||
private static long ANIMATE_TIME = 300L;
|
||||
|
||||
public static final int DIRECTION_LEFT = 0;
|
||||
public static final int DIRECTION_TOP = 1;
|
||||
public static final int DIRECTION_RIGHT = 2;
|
||||
public static final int DIRECTION_BOTTOM = 3;
|
||||
|
||||
private int mDirection;
|
||||
|
||||
private Animator mAnimator;
|
||||
|
||||
public SimpleCurtain(int direction) {
|
||||
mDirection = direction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(@NonNull final Scene enter, @NonNull final Scene exit) {
|
||||
final View enterSceneView = enter.getSceneView();
|
||||
enterSceneView.setVisibility(View.INVISIBLE);
|
||||
|
||||
enterSceneView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
ViewUtils.removeOnGlobalLayoutListener(enterSceneView.getViewTreeObserver(), this);
|
||||
|
||||
int width = enterSceneView.getWidth();
|
||||
int height = enterSceneView.getHeight();
|
||||
float translationX = 0f;
|
||||
float translationY = 0f;
|
||||
switch (mDirection) {
|
||||
case DIRECTION_LEFT:
|
||||
translationX = -width;
|
||||
break;
|
||||
case DIRECTION_TOP:
|
||||
translationY = -height;
|
||||
break;
|
||||
case DIRECTION_RIGHT:
|
||||
translationX = width;
|
||||
break;
|
||||
default:
|
||||
case DIRECTION_BOTTOM:
|
||||
translationY = height;
|
||||
break;
|
||||
}
|
||||
PropertyValuesHolder pvh;
|
||||
if (translationX != 0f) {
|
||||
pvh = PropertyValuesHolder.ofFloat("translationX", translationX, 0f);
|
||||
} else {
|
||||
pvh = PropertyValuesHolder.ofFloat("translationY", translationY, 0f);
|
||||
}
|
||||
Animator animator = ObjectAnimator.ofPropertyValuesHolder(enterSceneView, pvh);
|
||||
animator.setDuration(ANIMATE_TIME);
|
||||
animator.setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR);
|
||||
animator.addListener(new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
enterSceneView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
dispatchOpenFinished(enter, exit);
|
||||
hideSceneOnOpen(exit);
|
||||
mAnimator = null;
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
mAnimator = animator;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(@NonNull final Scene enter, @NonNull final Scene exit) {
|
||||
showSceneOnClose(enter);
|
||||
|
||||
final View exitSceneView = exit.getSceneView();
|
||||
int width = exitSceneView.getWidth();
|
||||
int height = exitSceneView.getHeight();
|
||||
float translationX = 0f;
|
||||
float translationY = 0f;
|
||||
switch (mDirection) {
|
||||
case DIRECTION_LEFT:
|
||||
translationX = -width;
|
||||
break;
|
||||
case DIRECTION_TOP:
|
||||
translationY = -height;
|
||||
break;
|
||||
case DIRECTION_RIGHT:
|
||||
translationX = width;
|
||||
break;
|
||||
default:
|
||||
case DIRECTION_BOTTOM:
|
||||
translationY = height;
|
||||
break;
|
||||
}
|
||||
PropertyValuesHolder pvh;
|
||||
if (translationX != 0f) {
|
||||
pvh = PropertyValuesHolder.ofFloat("translationX", 0f, translationX);
|
||||
} else {
|
||||
pvh = PropertyValuesHolder.ofFloat("translationY", 0f, translationY);
|
||||
}
|
||||
Animator animator = ObjectAnimator.ofPropertyValuesHolder(exitSceneView, pvh);
|
||||
animator.setDuration(ANIMATE_TIME);
|
||||
animator.setInterpolator(AnimationUtils.SLOW_FAST_INTERPOLATOR);
|
||||
animator.addListener(new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
dispatchCloseFinished(enter, exit);
|
||||
mAnimator = null;
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
mAnimator = animator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endAnimation() {
|
||||
if (mAnimator != null) {
|
||||
mAnimator.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInAnimation() {
|
||||
return mAnimator != null;
|
||||
}
|
||||
}
|
||||
@@ -110,6 +110,11 @@ public class SimpleDialog extends SceneDialog implements View.OnClickListener,
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean coverCompletely() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void bindDialog() {
|
||||
ListView listView = mListView;
|
||||
|
||||
@@ -192,6 +197,10 @@ public class SimpleDialog extends SceneDialog implements View.OnClickListener,
|
||||
mLayout.setFitPaddingBottom(b);
|
||||
}
|
||||
|
||||
public ViewGroup getLayout() {
|
||||
return mLayout;
|
||||
}
|
||||
|
||||
public CardView getCushion() {
|
||||
return mCushion;
|
||||
}
|
||||
|
||||
@@ -22,20 +22,22 @@ import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import com.hippo.animation.ArgbEvaluator;
|
||||
import com.hippo.animation.SimpleAnimatorListener;
|
||||
import com.hippo.util.AnimationUtils;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
import com.hippo.yorozuya.Say;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class SimpleDialogCurtain extends Curtain {
|
||||
|
||||
private static final String TAG = SimpleDialogCurtain.class.getSimpleName();
|
||||
|
||||
private static long ANIMATE_TIME = 300L;
|
||||
private static float SCALE_PERCENT = 0.75f;
|
||||
|
||||
private int mStartX;
|
||||
private int mStartY;
|
||||
@@ -57,14 +59,22 @@ public class SimpleDialogCurtain extends Curtain {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRebirth() {
|
||||
mStartX = 0;
|
||||
mStartY = 0;
|
||||
protected boolean needSpecifyPreviousScene() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(@NonNull final Scene enter, @NonNull final Scene exit) {
|
||||
AssertUtils.assertInstanceof("SimpleDialogCurtain should only use for SimpleDialog.", enter, SimpleDialog.class);
|
||||
|
||||
// Check stage layout isLayoutRequested
|
||||
final StageLayout stageLayout = enter.getStageLayout();
|
||||
if (!stageLayout.isLayoutRequested()) {
|
||||
Say.w(TAG, "WTF? stageLayout.isLayoutRequested() == false");
|
||||
dispatchOpenFinished(enter, exit);
|
||||
return;
|
||||
}
|
||||
|
||||
final SimpleDialog enterDialog = (SimpleDialog) enter;
|
||||
|
||||
final Set<Animator> animatorCollection = new HashSet<>();
|
||||
@@ -87,13 +97,10 @@ public class SimpleDialogCurtain extends Curtain {
|
||||
cushion.setVisibility(View.INVISIBLE);
|
||||
frame.setVisibility(View.INVISIBLE);
|
||||
|
||||
// TODO addOnGlobalLayoutListener is not reliable
|
||||
// TODO use isLayoutRequested
|
||||
// TODO if isLayoutRequested return false, try to use StageView Size
|
||||
frame.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
stageLayout.addOnLayoutListener(new StageLayout.OnLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
ViewUtils.removeOnGlobalLayoutListener(frame.getViewTreeObserver(), this);
|
||||
public void onLayout(View view) {
|
||||
stageLayout.removeOnLayoutListener(this);
|
||||
|
||||
float floatStartX;
|
||||
float floatStartY;
|
||||
@@ -141,6 +148,7 @@ public class SimpleDialogCurtain extends Curtain {
|
||||
cushion.setVisibility(View.VISIBLE);
|
||||
frame.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
dispatchOpenFinished(enter, exit);
|
||||
@@ -168,44 +176,48 @@ public class SimpleDialogCurtain extends Curtain {
|
||||
animatorCollection.add(colorAnim);
|
||||
colorAnim.setInterpolator(AnimationUtils.SLOW_FAST_INTERPOLATOR);
|
||||
|
||||
final View layout = exitDialog.getLayout();
|
||||
final View cushion = exitDialog.getCushion();
|
||||
final View frame = exitDialog.getFrame();
|
||||
AssertUtils.assertNotNull("Cushion view must not be null.", cushion);
|
||||
AssertUtils.assertNotNull("Frame view must not be null.", frame);
|
||||
|
||||
float floatEndX;
|
||||
float floatEndY;
|
||||
int intEndX;
|
||||
int intEndY;
|
||||
if (mStartX == 0 && mStartY == 0) {
|
||||
int[] center = new int[2];
|
||||
exitDialog.getCenterLocation(center);
|
||||
floatEndX = center[0];
|
||||
floatEndY = center[1];
|
||||
intEndX = center[0];
|
||||
intEndY = center[1];
|
||||
// Check stage layout isLayoutRequested
|
||||
final StageLayout stageLayout = enter.getStageLayout();
|
||||
if (stageLayout.isLayoutRequested()) {
|
||||
stageLayout.addOnLayoutListener(new StageLayout.OnLayoutListener() {
|
||||
@Override
|
||||
public void onLayout(View view) {
|
||||
onClose(enter, exitDialog, layout, cushion, frame, animatorCollection);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
floatEndX = mStartX;
|
||||
floatEndY = mStartY;
|
||||
intEndX = mStartX;
|
||||
intEndY = mStartY;
|
||||
onClose(enter, exitDialog, layout, cushion, frame, animatorCollection);
|
||||
}
|
||||
}
|
||||
|
||||
cushion.setPivotX(0f);
|
||||
cushion.setPivotY(0f);
|
||||
PropertyValuesHolder scaleXPvh = PropertyValuesHolder.ofFloat("scaleX", 0f);
|
||||
PropertyValuesHolder scaleYPvh = PropertyValuesHolder.ofFloat("scaleY", 0f);
|
||||
PropertyValuesHolder xPvh = PropertyValuesHolder.ofFloat("x", floatEndX);
|
||||
PropertyValuesHolder yPvh = PropertyValuesHolder.ofFloat("y", floatEndY);
|
||||
ObjectAnimator animCushion = ObjectAnimator.ofPropertyValuesHolder(cushion, scaleXPvh, scaleYPvh, xPvh, yPvh);
|
||||
private void onClose(final Scene enter, final SimpleDialog exitDialog, View layout, View cushion, View frame, Set<Animator> animatorCollection) {
|
||||
|
||||
layout.setAlpha(1f);
|
||||
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(layout, "alpha", 1f, 0f);
|
||||
alphaAnim.setDuration(ANIMATE_TIME);
|
||||
animatorCollection.add(alphaAnim);
|
||||
|
||||
cushion.setPivotX(cushion.getWidth() / 2);
|
||||
cushion.setPivotY(cushion.getHeight() / 2);
|
||||
PropertyValuesHolder scaleXPvh = PropertyValuesHolder.ofFloat("scaleX", 1f, SCALE_PERCENT);
|
||||
PropertyValuesHolder scaleYPvh = PropertyValuesHolder.ofFloat("scaleY", 1f, SCALE_PERCENT);
|
||||
ObjectAnimator animCushion = ObjectAnimator.ofPropertyValuesHolder(cushion, scaleXPvh, scaleYPvh);
|
||||
animCushion.setDuration(ANIMATE_TIME);
|
||||
animCushion.setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR);
|
||||
animatorCollection.add(animCushion);
|
||||
|
||||
PropertyValuesHolder leftPvh = PropertyValuesHolder.ofInt("drawLeft", intEndX);
|
||||
PropertyValuesHolder topPvh = PropertyValuesHolder.ofInt("drawTop", intEndY);
|
||||
PropertyValuesHolder rightPvh = PropertyValuesHolder.ofInt("drawRight", intEndX);
|
||||
PropertyValuesHolder bottomPvh = PropertyValuesHolder.ofInt("drawBottom", intEndY);
|
||||
int dx = (int) (frame.getWidth() * (1 - SCALE_PERCENT) / 2);
|
||||
int dy = (int) (frame.getHeight() * (1 - SCALE_PERCENT) / 2);
|
||||
PropertyValuesHolder leftPvh = PropertyValuesHolder.ofInt("drawLeft", frame.getLeft() + dx);
|
||||
PropertyValuesHolder topPvh = PropertyValuesHolder.ofInt("drawTop", frame.getTop() + dy);
|
||||
PropertyValuesHolder rightPvh = PropertyValuesHolder.ofInt("drawRight", frame.getRight() - dx);
|
||||
PropertyValuesHolder bottomPvh = PropertyValuesHolder.ofInt("drawBottom", frame.getBottom() - dy);
|
||||
ObjectAnimator animFrame = ObjectAnimator.ofPropertyValuesHolder(frame, leftPvh, topPvh, rightPvh, bottomPvh);
|
||||
animFrame.setDuration(ANIMATE_TIME);
|
||||
animFrame.setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR);
|
||||
@@ -216,7 +228,7 @@ public class SimpleDialogCurtain extends Curtain {
|
||||
mAnimatorSet.addListener(new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
dispatchCloseFinished(enter, exit);
|
||||
dispatchCloseFinished(enter, exitDialog);
|
||||
mAnimatorSet = null;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -21,10 +21,17 @@ import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class StageLayout extends FrameLayout {
|
||||
|
||||
private List<OnLayoutListener> mOnLayoutListeners = new ArrayList<>(3);
|
||||
private List<OnLayoutListener> mOnLayoutListenersCopy = new ArrayList<>(3);
|
||||
|
||||
public StageLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
@@ -46,4 +53,31 @@ public class StageLayout extends FrameLayout {
|
||||
protected void dispatchRestoreInstanceState(@NonNull SparseArray<Parcelable> container) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
public void addOnLayoutListener(OnLayoutListener layoutListener) {
|
||||
mOnLayoutListeners.add(layoutListener);
|
||||
}
|
||||
|
||||
public void removeOnLayoutListener(OnLayoutListener layoutListener) {
|
||||
mOnLayoutListeners.remove(layoutListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t,
|
||||
int r, int b) {
|
||||
super.onLayout(changed, l, t, r, b);
|
||||
|
||||
mOnLayoutListenersCopy.clear();
|
||||
for (int i = 0, n = mOnLayoutListeners.size(); i < n; i++) {
|
||||
mOnLayoutListenersCopy.add(mOnLayoutListeners.get(i));
|
||||
}
|
||||
for (OnLayoutListener listener : mOnLayoutListenersCopy) {
|
||||
listener.onLayout(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface OnLayoutListener {
|
||||
void onLayout(View view);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.scene;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
public class UnionCurtain extends Curtain {
|
||||
|
||||
private Curtain mOpenCurtain;
|
||||
private Curtain mCloseCurtain;
|
||||
|
||||
public UnionCurtain(Curtain openCurtain, Curtain closeCurtain) {
|
||||
mOpenCurtain = openCurtain;
|
||||
mCloseCurtain = closeCurtain;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setPreviousScene(@Nullable Scene pScene) {
|
||||
super.setPreviousScene(pScene);
|
||||
|
||||
mOpenCurtain.setPreviousScene(pScene);
|
||||
mCloseCurtain.setPreviousScene(pScene);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean needSpecifyPreviousScene() {
|
||||
return mCloseCurtain.needSpecifyPreviousScene();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRebirth() {
|
||||
mCloseCurtain.onRebirth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(@NonNull Scene enter, @NonNull Scene exit) {
|
||||
mOpenCurtain.open(enter, exit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(@NonNull Scene enter, @NonNull Scene exit) {
|
||||
mCloseCurtain.close(enter, exit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endAnimation() {
|
||||
mOpenCurtain.endAnimation();
|
||||
mCloseCurtain.endAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInAnimation() {
|
||||
return mOpenCurtain.isInAnimation() || mCloseCurtain.isInAnimation();
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,6 @@ import android.widget.TextView;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.rippleold.RippleSalon;
|
||||
import com.hippo.scene.AppbarScene;
|
||||
import com.hippo.scene.SimpleCurtain;
|
||||
import com.hippo.scene.StageActivity;
|
||||
import com.hippo.widget.recyclerview.EasyRecyclerView;
|
||||
|
||||
@@ -66,7 +65,7 @@ public class PreferenceHeaderScene extends AppbarScene {
|
||||
if (clazz == null) {
|
||||
return false;
|
||||
} else {
|
||||
startScene(clazz, null, new SimpleCurtain(SimpleCurtain.DIRECTION_BOTTOM));
|
||||
startScene(clazz);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Hippo Seven
|
||||
*
|
||||
* 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.hippo.widget;
|
||||
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
public class GlobalLayoutSet {
|
||||
|
||||
private OnAllLayoutListener mOnAllLayoutListener;
|
||||
|
||||
private int mSize;
|
||||
|
||||
public void setOnAllLayoutListener(OnAllLayoutListener listener) {
|
||||
mOnAllLayoutListener = listener;
|
||||
}
|
||||
|
||||
public void addListenerToObserver(ViewTreeObserver observer) {
|
||||
LayoutListener ll = new LayoutListener(observer);
|
||||
observer.addOnGlobalLayoutListener(ll);
|
||||
mSize++;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
private class LayoutListener implements ViewTreeObserver.OnGlobalLayoutListener {
|
||||
private ViewTreeObserver mObserver;
|
||||
|
||||
private LayoutListener(ViewTreeObserver observer) {
|
||||
mObserver = observer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
ViewUtils.removeOnGlobalLayoutListener(mObserver, this);
|
||||
|
||||
if (--mSize == 0) {
|
||||
mOnAllLayoutListener.onAllLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnAllLayoutListener {
|
||||
void onAllLayout();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user