Android上实现各种折叠效果的demo,废话不多说,直接上代码了源码:https://github.com/openaphid/android-flip.git

/*Copyright 2012 Aphid MobileLicensed 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.0Unless required by applicable law or agreed to in writing, softwaredistributed 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 andlimitations under the License. */package com.aphidmobile.flip.demo;import android.app.Activity;import android.app.ListActivity;import android.content.Intent;import android.net.Uri;import android.os.Bundle;import android.view.*;import android.widget.ListView;import android.widget.SimpleAdapter;import com.aphidmobile.flipview.demo.R;import java.util.*;public class MainActivity extends ListActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setListAdapter(new SimpleAdapter(this, getData(), android.R.layout.simple_list_item_1, new String[]{"title"}, new int[]{android.R.id.text1}));getListView().setScrollbarFadingEnabled(false);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {Intent intent = new Intent(Intent.ACTION_VIEW,Uri.parse("http://openaphid.github.com/"));startActivity(intent);return true;}@SuppressWarnings("unchecked")@Overrideprotected void onListItemClick(ListView l, View v, int position, long id) {Map<String, Object> map = (Map<String, Object>) l.getItemAtPosition(position);Intent intent = new Intent(this, (Class<? extends Activity>)map.get("activity"));startActivity(intent);}private List<? extends Map<String, ?>> getData() {List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();addItem(data, "TextViews", FlipTextViewActivity.class);addItem(data, "Buttons", FlipButtonActivity.class);addItem(data, "Complex Layouts", FlipComplexLayoutActivity.class);addItem(data, "Async Content", FlipAsyncContentActivity.class);addItem(data, "Event Listener", FlipTextViewAltActivity.class);addItem(data, "Horizontal", FlipHorizontalLayoutActivity.class);addItem(data, "Issue #5", Issue5Activity.class);addItem(data, "XML Configuration", FlipTextViewXmlActivity.class);addItem(data, "Fragment", FlipFragmentActivity.class);addItem(data, "Dynamic Adapter Size", FlipDynamicAdapterActivity.class);return data;}private void addItem(List<Map<String, Object>> data, String title, Class<? extends Activity> activityClass) {Map<String, Object> map = new HashMap<String, Object>();map.put("title", data.size() + ". " + title);map.put("activity", activityClass);data.add(map);}}
FlipViewController.java 外部引用原始文档
  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
/*Copyright 2012 Aphid MobileLicensed 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.0Unless required by applicable law or agreed to in writing, softwaredistributed 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 andlimitations under the License. */package com.aphidmobile.flip;import android.content.Context;import android.content.res.Configuration;import android.content.res.TypedArray;import android.database.DataSetObserver;import android.graphics.Bitmap;import android.graphics.PixelFormat;import android.opengl.GLSurfaceView;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.view.*;import android.widget.AbsListView;import android.widget.Adapter;import android.widget.AdapterView;import com.aphidmobile.utils.AphidLog;import com.openaphid.flip.R;import junit.framework.Assert;import java.util.LinkedList;public class FlipViewController extends AdapterView<Adapter> {public static final int VERTICAL = 0;public static final int HORIZONTAL = 1;public static interface ViewFlipListener {void onViewFlipped(View view, int position);}private static final int MAX_RELEASED_VIEW_SIZE = 1;private static final int MSG_SURFACE_CREATED = 1;private Handler handler = new Handler(new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {if (msg.what == MSG_SURFACE_CREATED) {contentWidth = 0;contentHeight = 0;requestLayout();return true;}return false;}});private GLSurfaceView surfaceView;private FlipRenderer renderer;private FlipCards cards;private int contentWidth;private int contentHeight;@ViewDebug.ExportedPropertyprivate int flipOrientation;private boolean inFlipAnimation = false;//AdapterView Relatedprivate Adapter adapter;private int adapterDataCount = 0;private DataSetObserver adapterDataObserver;private final LinkedList<View> bufferedViews = new LinkedList<View>();private final LinkedList<View> releasedViews = new LinkedList<View>(); //XXX: use a SparseArray to keep the related view indices?private int bufferIndex = -1;private int adapterIndex = -1;private int sideBufferSize = 1;private float touchSlop;private ViewFlipListener onViewFlipListener;@ViewDebug.ExportedPropertyprivate Bitmap.Config animationBitmapFormat = Bitmap.Config.ARGB_8888;public FlipViewController(Context context) {this(context, VERTICAL);}public FlipViewController(Context context, int flipOrientation) {super(context);init(context, flipOrientation);}/** * Constructor required for XML inflation. */public FlipViewController(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);int orientation = VERTICAL;TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.FlipViewController, 0, 0);try {int value = a.getInteger(R.styleable.FlipViewController_orientation, VERTICAL);if (value == HORIZONTAL)orientation = HORIZONTAL;value = a.getInteger(R.styleable.FlipViewController_animationBitmapFormat, 0);if (value == 1)setAnimationBitmapFormat(Bitmap.Config.ARGB_4444);else if (value == 2)setAnimationBitmapFormat(Bitmap.Config.RGB_565);elsesetAnimationBitmapFormat(Bitmap.Config.ARGB_8888);} finally {a.recycle();}init(context, orientation);}/** * Constructor required for XML inflation. */public FlipViewController(Context context, AttributeSet attrs) {this(context, attrs, 0);}private void init(Context context, int orientation) {ViewConfiguration configuration = ViewConfiguration.get(getContext());touchSlop = configuration.getScaledTouchSlop();this.flipOrientation = orientation;setupSurfaceView(context);}public Bitmap.Config getAnimationBitmapFormat() {return animationBitmapFormat;}/** * Set the bitmap config for the animation, default is ARGB_8888, which provides the best quality with large peak memory consumption. * * @param animationBitmapFormat ALPHA_8 is not supported and will throw exception when binding textures */public void setAnimationBitmapFormat(Bitmap.Config animationBitmapFormat) {this.animationBitmapFormat = animationBitmapFormat;}public ViewFlipListener getOnViewFlipListener() {return onViewFlipListener;}public void setOnViewFlipListener(ViewFlipListener onViewFlipListener) {this.onViewFlipListener = onViewFlipListener;}public void onResume() {surfaceView.onResume();}public void onPause() {surfaceView.onPause();}/** * Request the animator to update display if the pageView has been preloaded. * <p/> * If the pageView is being used in the animation or its content has been buffered, the animator forcibly reloads it. * <p/> * The reloading process is a bit heavy for an active page, so please don't invoke it too frequently for an active page. The cost is trivial for inactive pages. * * @param pageView */public void refreshPage(View pageView) {if (cards.refreshPageView(pageView))requestLayout();}/** * @param pageIndex * @see #refreshPage(android.view.View) */public void refreshPage(int pageIndex) {if (cards.refreshPage(pageIndex))requestLayout();}/** * Force the animator reload all preloaded pages */public void refreshAllPages() {cards.refreshAllPages();requestLayout();}//--------------------------------------------------------------------------------------------------------------------// Touch Event@Overridepublic boolean onInterceptTouchEvent(MotionEvent event) {return cards.handleTouchEvent(event, false);}@Overridepublic boolean onTouchEvent(MotionEvent event) {return cards.handleTouchEvent(event, true);}//--------------------------------------------------------------------------------------------------------------------// Orientation@Overrideprotected void onConfigurationChanged(Configuration newConfig) {super.onConfigurationChanged(newConfig);//XXX: adds a global layout listener?}//--------------------------------------------------------------------------------------------------------------------// AdapterView<Adapter>@Overridepublic Adapter getAdapter() {return adapter;}@Overridepublic void setAdapter(Adapter adapter) {setAdapter(adapter, 0);}public void setAdapter(Adapter adapter, int initialPosition) {if (this.adapter != null)this.adapter.unregisterDataSetObserver(adapterDataObserver);Assert.assertNotNull("adapter should not be null", adapter);this.adapter = adapter;adapterDataCount = adapter.getCount();adapterDataObserver = new MyDataSetObserver();this.adapter.registerDataSetObserver(adapterDataObserver);if (adapterDataCount > 0)setSelection(initialPosition);}@Overridepublic View getSelectedView() {return (bufferIndex < bufferedViews.size() && bufferIndex >= 0) ? bufferedViews.get(bufferIndex) : null;}@Overridepublic void setSelection(int position) {if (adapter == null)return;Assert.assertTrue("Invalid selection position", position >= 0 && position < adapterDataCount);releaseViews();View selectedView = viewFromAdapter(position, true);bufferedViews.add(selectedView);for (int i = 1; i <= sideBufferSize; i++) {int previous = position - i;int next = position + i;if (previous >= 0)bufferedViews.addFirst(viewFromAdapter(previous, false));if (next < adapterDataCount)bufferedViews.addLast(viewFromAdapter(next, true));}bufferIndex = bufferedViews.indexOf(selectedView);adapterIndex = position;requestLayout();updateVisibleView(inFlipAnimation ? -1 : bufferIndex);cards.resetSelection(position, adapterDataCount);}@Overridepublic int getSelectedItemPosition() {return adapterIndex;}//--------------------------------------------------------------------------------------------------------------------// Layout@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {if (AphidLog.ENABLE_DEBUG)AphidLog.d("onLayout: %d, %d, %d, %d; child %d", l, t, r, b, bufferedViews.size());for (View child : bufferedViews)child.layout(0, 0, r - l, b - t);if (changed || contentWidth == 0) {int w = r - l;int h = b - t;surfaceView.layout(0, 0, w, h);if (contentWidth != w || contentHeight != h) {contentWidth = w;contentHeight = h;}}if (bufferedViews.size() >= 1) {View frontView = bufferedViews.get(bufferIndex);View backView = null;if (bufferIndex < bufferedViews.size() - 1)backView = bufferedViews.get(bufferIndex + 1);renderer.updateTexture(adapterIndex, frontView, backView == null ? -1 : adapterIndex + 1, backView);}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);for (View child : bufferedViews)child.measure(widthMeasureSpec, heightMeasureSpec);surfaceView.measure(widthMeasureSpec, heightMeasureSpec);}//--------------------------------------------------------------------------------------------------------------------//internal exposed properties & methodsfloat getTouchSlop() {return touchSlop;}GLSurfaceView getSurfaceView() {return surfaceView;}FlipRenderer getRenderer() {return renderer;}int getContentWidth() {return contentWidth;}int getContentHeight() {return contentHeight;}void reloadTexture() {handler.sendMessage(Message.obtain(handler, MSG_SURFACE_CREATED));}//--------------------------------------------------------------------------------------------------------------------// Internalsprivate void setupSurfaceView(Context context) {surfaceView = new GLSurfaceView(getContext());cards = new FlipCards(this, flipOrientation == VERTICAL);renderer = new FlipRenderer(this, cards);surfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);surfaceView.setZOrderOnTop(true);surfaceView.setRenderer(renderer);surfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);surfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);addViewInLayout(surfaceView, -1, new AbsListView.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT), false);}private void releaseViews() {for (View view : bufferedViews)releaseView(view);bufferedViews.clear();bufferIndex = -1;adapterIndex = -1;}private void releaseView(View view) {Assert.assertNotNull(view);detachViewFromParent(view);addReleasedView(view);}private void addReleasedView(View view) {Assert.assertNotNull(view);if (releasedViews.size() < MAX_RELEASED_VIEW_SIZE)releasedViews.add(view);}private View viewFromAdapter(int position, boolean addToTop) {Assert.assertNotNull(adapter);View releasedView = releasedViews.isEmpty() ? null : releasedViews.removeFirst();View view = adapter.getView(position, releasedView, this);if (releasedView != null && view != releasedView)addReleasedView(releasedView);setupAdapterView(view, addToTop, view == releasedView);return view;}private void setupAdapterView(View view, boolean addToTop, boolean isReusedView) {LayoutParams params = view.getLayoutParams();if (params == null) {params = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0);}if (isReusedView)attachViewToParent(view, addToTop ? 0 : 1, params);elseaddViewInLayout(view, addToTop ? 0 : 1, params, true);}private void updateVisibleView(int index) {/*if (AphidLog.ENABLE_DEBUG)AphidLog.d("Update visible views, index %d, buffered: %d, adapter %d", index, bufferedViews.size(), adapterIndex);*/for (int i = 0; i < bufferedViews.size(); i++)bufferedViews.get(i).setVisibility(index == i ? VISIBLE : INVISIBLE);}private void debugBufferedViews() {if (AphidLog.ENABLE_DEBUG)AphidLog.d("bufferedViews: %s; buffer index %d, adapter index %d", bufferedViews, bufferIndex, adapterIndex);}void postFlippedToView(final int indexInAdapter) {handler.post(new Runnable() {@Overridepublic void run() {flippedToView(indexInAdapter, true);}});}void flippedToView(final int indexInAdapter, boolean isPost) {if (AphidLog.ENABLE_DEBUG)AphidLog.d("flippedToView: %d, isPost %s", indexInAdapter, isPost);debugBufferedViews();if (indexInAdapter >= 0 && indexInAdapter < adapterDataCount) {if (indexInAdapter == adapterIndex + 1) { //forward one pageif (adapterIndex < adapterDataCount - 1) {adapterIndex++;View old = bufferedViews.get(bufferIndex);if (bufferIndex > 0)releaseView(bufferedViews.removeFirst());if (adapterIndex + sideBufferSize < adapterDataCount)bufferedViews.addLast(viewFromAdapter(adapterIndex + sideBufferSize, true));bufferIndex = bufferedViews.indexOf(old) + 1;requestLayout();updateVisibleView(inFlipAnimation ? -1 : bufferIndex);}} else if (indexInAdapter == adapterIndex - 1) {if (adapterIndex > 0) {adapterIndex--;View old = bufferedViews.get(bufferIndex);if (bufferIndex < bufferedViews.size() - 1)releaseView(bufferedViews.removeLast());if (adapterIndex - sideBufferSize >= 0)bufferedViews.addFirst(viewFromAdapter(adapterIndex - sideBufferSize, false));bufferIndex = bufferedViews.indexOf(old) - 1;requestLayout();updateVisibleView(inFlipAnimation ? -1 : bufferIndex);}} else {AphidLog.e("Should not happen: indexInAdapter %d, adapterIndex %d", indexInAdapter, adapterIndex);}} elseAssert.fail("Invalid indexInAdapter: " + indexInAdapter);//debugBufferedViews();}void showFlipAnimation() {if (!inFlipAnimation) {inFlipAnimation = true;cards.setVisible(true);surfaceView.requestRender();handler.postDelayed(new Runnable() { //use a delayed message to avoid flicker, the perfect solution would be sending a message from the GL thread public void run() {if (inFlipAnimation)updateVisibleView(-1);}}, 100);}}void postHideFlipAnimation() {if (inFlipAnimation) {handler.post(new Runnable() {@Overridepublic void run() {hideFlipAnimation();}});}}private void hideFlipAnimation() {if (inFlipAnimation) {inFlipAnimation = false;updateVisibleView(bufferIndex);if (onViewFlipListener != null)onViewFlipListener.onViewFlipped(bufferedViews.get(bufferIndex), adapterIndex);handler.post(new Runnable() {public void run() {if (!inFlipAnimation) {cards.setVisible(false);surfaceView.requestRender(); //ask OpenGL to clear its display}}});}}private void onDataChanged() {adapterDataCount = adapter.getCount();int activeIndex;if (adapterIndex < 0)activeIndex = 0;elseactiveIndex = Math.min(adapterIndex, adapterDataCount - 1);releaseViews();setSelection(activeIndex);}private class MyDataSetObserver extends DataSetObserver {@Overridepublic void onChanged() {onDataChanged();}@Overridepublic void onInvalidated() {onDataChanged();}}}
6666666666666.png 外部引用原始文档 44444444.png 外部引用原始文档 55555555.png 外部引用原始文档

更多相关文章

  1. C#移动端开发之Xamarin.Forms使用文档(从安装到发布APK安装包)
  2. android帮助文档打开慢的解决方法
  3. Android创建XML文档
  4. Android NDK rb5 文档之使用 Android 工具链作为一个独立编译器
  5. Android 文档的阅读顺序!
  6. Android 文档的阅读顺序
  7. Android 官方 Training 文档学习总结系列之「My First App涉及知

随机推荐

  1. Android(安卓)内存优化代码篇总结
  2. Android(安卓)Socket 发送与接收数据问题
  3. Hbuilder集成个推时Android和ISO中推送的
  4. Android实现无线调试自己的应用
  5. Android(安卓)View中的控件和监听方法...
  6. Android(安卓)按键映射 驱动
  7. Android动态获取资源ID并使用javabean进
  8. android 地铁最短路线换乘查询系统(1)
  9. android adb的配置以及 java环境变量的配
  10. Androd学习笔记——新浪微博Android(安卓