Add GalleryView

This commit is contained in:
seven332 committed 2015-07-19 15:19:49 +08:00
1 parent 440898fba5
commit 87e3db3dc5
6 files changed
+391 -5

No files matched your search

@@ -0,0 +1,341 @@
/*
* 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.ehviewer.gallery.widget;
import android.content.Context;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.hippo.ehviewer.R;
import com.hippo.yorozuya.LayoutUtils;
import com.hippo.yorozuya.MathUtils;
import com.hippo.yorozuya.Say;
public class GalleryView extends RecyclerView {
private static final String TAG = GalleryView.class.getSimpleName();
private static int INTERVAL_DP = 32;
private Mode mMode;
private int mHalfInterval;
private int mSize = 20;
private GalleryAdapter mAdapter;
private GalleryLayoutManager mLayoutManager;
public enum Mode {
LEFT_TO_RIGHT,
RIGHT_TO_LEFT,
TOP_TO_BOTTOM
}
public GalleryView(Context context) {
super(context);
init(context);
}
public GalleryView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public GalleryView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
mHalfInterval = LayoutUtils.dp2pix(context, INTERVAL_DP) / 2;
mLayoutManager = new GalleryLayoutManager(context);
setLayoutManager(mLayoutManager);
mAdapter = new GalleryAdapter();
setAdapter(mAdapter);
addItemDecoration(new IntervalDecoration());
addOnScrollListener(new ScrollListener());
setHasFixedSize(true);
setMode(Mode.RIGHT_TO_LEFT);
}
public void setMode(Mode mode) {
mMode = mode;
if (mMode == Mode.LEFT_TO_RIGHT) {
mLayoutManager.setOrientation(HORIZONTAL);
mLayoutManager.setReverseLayout(false);
} else if (mMode == Mode.RIGHT_TO_LEFT) {
mLayoutManager.setOrientation(HORIZONTAL);
mLayoutManager.setReverseLayout(true);
} else if (mMode == Mode.TOP_TO_BOTTOM) {
mLayoutManager.setOrientation(VERTICAL);
mLayoutManager.setReverseLayout(false);
}
// Not all DecorInset will be updated at once, so do it by myself
int length = getChildCount();
for (int i = 0; i < length; i++) {
((RecyclerView.LayoutParams) getChildAt(i).getLayoutParams()).mInsetsDirty = true;
}
}
@Override
public boolean fling(int velocityX, int velocityY) {
if (mMode == Mode.TOP_TO_BOTTOM) {
return super.fling(velocityX, velocityY);
} else {
return false;
}
}
// Only work for Mode.LEFT_TO_RIGHT and Mode.RIGHT_TO_LEFT
private View findCenterXView() {
int centerX = getWidth() / 2;
int length = getChildCount();
for (int i = 0; i < length; i++) {
View v = getChildAt(i);
if (v.getLeft() < centerX && v.getRight() >= centerX) {
return v;
}
}
return null;
}
// Only work for Mode.LEFT_TO_RIGHT and Mode.RIGHT_TO_LEFT
private int getOffsetToPage(int page) throws Exception {
View v = findCenterXView();
if (v == null) {
throw new Exception("Can't find center view");
}
int currentPage = getChildAdapterPosition(v);
if (currentPage == RecyclerView.NO_POSITION) {
throw new Exception("Can't find current page");
}
int d = page - currentPage;
if (mMode == Mode.RIGHT_TO_LEFT) {
d = -d;
}
return d * (mHalfInterval * 2 + getWidth()) + v.getLeft();
}
public void smoothScrollToPage(int page) {
if (mMode == Mode.TOP_TO_BOTTOM) {
smoothScrollToPosition(page);
} else {
page = MathUtils.clamp(page, 0, mSize - 1);
try {
int offsetX = getOffsetToPage(page);
smoothScrollBy(offsetX, 0);
} catch (Exception e) {
Say.d(TAG, e.getMessage());
smoothScrollToPosition(page);
}
}
}
public void scrollToPage(int page) {
if (mMode == Mode.TOP_TO_BOTTOM) {
scrollToPosition(page);
} else {
page = MathUtils.clamp(page, 0, mSize - 1);
try {
int offsetX = getOffsetToPage(page);
scrollBy(offsetX, 0);
} catch (Exception e) {
Say.d(TAG, e.getMessage());
scrollToPosition(page);
}
}
}
public int getCurrentPage() {
if (mMode == Mode.TOP_TO_BOTTOM) {
return mLayoutManager.findFirstVisibleItemPosition();
} else {
View v = findCenterXView();
if (v == null) {
return RecyclerView.NO_POSITION;
} else {
return getChildLayoutPosition(v);
}
}
}
class GalleryHolder extends RecyclerView.ViewHolder {
private ImageView imageView;
public GalleryHolder(View itemView) {
super(itemView);
imageView = (ImageView) itemView;
}
}
class GalleryAdapter extends RecyclerView.Adapter<GalleryHolder> {
@Override
public GalleryHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new GalleryHolder(new ImageView(getContext()));
}
@Override
public void onBindViewHolder(GalleryHolder holder, int position) {
holder.imageView.setImageDrawable(getResources().getDrawable(position == 0 ?
R.drawable.ic_heart : R.drawable.ic_sad));
}
@Override
public int getItemCount() {
return mSize;
}
}
class GalleryLayoutManager extends LinearLayoutManager {
public GalleryLayoutManager(Context context) {
super(context);
}
@Override
public void measureChildWithMargins(View child, int widthUsed, int heightUsed) {
// Call it to update decor
getItemDecorInsetsForChild(child);
int widthSpec;
int heightSpec;
// LayoutParams is useless
if (mMode == Mode.TOP_TO_BOTTOM) {
widthSpec = View.MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY);
heightSpec = View.MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST);
} else {
widthSpec = View.MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY);
heightSpec = View.MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY);
}
child.measure(widthSpec, heightSpec);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
super.onLayoutChildren(recycler, state);
// Ensure page is in center
if (mMode == Mode.LEFT_TO_RIGHT || mMode == Mode.RIGHT_TO_LEFT) {
scrollToPage(getCurrentPage());
}
}
}
class ScrollListener extends OnScrollListener {
private int mCurrentPage = RecyclerView.NO_POSITION;
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (mMode == Mode.TOP_TO_BOTTOM) {
// Nothing to do
return;
}
if (newState == SCROLL_STATE_DRAGGING) {
mCurrentPage = getCurrentPage();
} else if (newState == SCROLL_STATE_IDLE) {
if (mCurrentPage != RecyclerView.NO_POSITION) {
ViewHolder viewHolder = findViewHolderForLayoutPosition(mCurrentPage);
if (viewHolder == null) {
// WTF?
Say.w(TAG, "Can't find ViewHolder when adjustPosition");
smoothScrollToPage(mCurrentPage);
} else {
View v = viewHolder.itemView;
int scrollX;
int interval = mHalfInterval * 2;
int left = v.getLeft();
int width = getWidth();
if (left > interval &&
((mMode == Mode.LEFT_TO_RIGHT && mCurrentPage > 0) ||
(mMode == Mode.RIGHT_TO_LEFT && mCurrentPage < mSize - 1))) { // Scroll left
scrollX = -width - interval + left;
} else if (left < -interval &&
((mMode == Mode.LEFT_TO_RIGHT && mCurrentPage < mSize - 1) ||
(mMode == Mode.RIGHT_TO_LEFT && mCurrentPage > 0))) { // Scroll right
scrollX = width + interval + left;
} else {
scrollX = left;
}
smoothScrollBy(scrollX, 0);
}
mCurrentPage = RecyclerView.NO_POSITION;
}
}
}
}
class IntervalDecoration extends RecyclerView.ItemDecoration {
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
int index = getChildLayoutPosition(view);
if (mMode == Mode.LEFT_TO_RIGHT) {
if (index == 0) {
outRect.left = 0;
} else {
outRect.left = mHalfInterval;
}
if (index == mSize - 1) {
outRect.right = 0;
} else {
outRect.right = mHalfInterval;
}
outRect.top = 0;
outRect.bottom = 0;
} else if (mMode == Mode.RIGHT_TO_LEFT) {
if (index == 0) {
outRect.right = 0;
} else {
outRect.right = mHalfInterval;
}
if (index == mSize - 1) {
outRect.left = 0;
} else {
outRect.left = mHalfInterval;
}
outRect.top = 0;
outRect.bottom = 0;
} else if (mMode == Mode.TOP_TO_BOTTOM) {
if (index == 0) {
outRect.top = 0;
} else {
outRect.top = mHalfInterval;
}
if (index == mSize - 1) {
outRect.bottom = 0;
} else {
outRect.bottom = mHalfInterval;
}
outRect.left = 0;
outRect.right = 0;
}
}
}
}
@@ -16,7 +16,17 @@
package com.hippo.ehviewer.ui;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.hippo.ehviewer.R;
public class GalleryActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gallery);
}
}
@@ -18,6 +18,7 @@ package com.hippo.ehviewer.ui.scene;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.text.Html;
@@ -47,6 +48,7 @@ import com.hippo.ehviewer.client.data.GalleryDetail;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.client.data.PreviewSet;
import com.hippo.ehviewer.client.data.TagGroup;
import com.hippo.ehviewer.ui.GalleryActivity;
import com.hippo.ehviewer.util.EhUtils;
import com.hippo.ehviewer.util.Settings;
import com.hippo.ehviewer.widget.LoadImageView;
@@ -278,9 +280,8 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener,
}
if (v == mRead) {
Announcer announcer = new Announcer();
announcer.putExtra(GalleryScene.KEY_GALLERY_BASE, mGalleryDetail);
startScene(GalleryScene.class, announcer);
Intent intent = new Intent(getStageActivity(), GalleryActivity.class);
getStageActivity().startActivity(intent);
} else if (v == mDownload) {
} else if (v == mFavorite) {