Android实现仿支付宝流水
来源:互联网 发布:java web是什么 编辑:程序博客网 时间:2024/05/16 17:31
今天给大家讲的是如何自定义下拉的ListView实现支付宝账单的效果,月份是需要悬浮的,然后没一个月归为一类,先看一个效果图吧。
场景:后台下发的数据就是一个List<对象>,考虑到实际情况,还需要做下拉的分页操作,所以,基于上面的情况,我们需要自定义一个可以拦截月份的view。
先定义一个FooterView类。
public class ListViewFooter extends LinearLayout { public final static int STATE_NORMAL = 0; public final static int STATE_READY = 1; public final static int STATE_LOADING = 2; private Context mContext; private View mContentView; private View mProgressBar; private TextView mFootTextView; public ListViewFooter(Context context) { super(context); initView(context); } public ListViewFooter(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } //下拉状态处理 public void setState(int state) { mFootTextView.setVisibility(View.INVISIBLE); mProgressBar.setVisibility(View.GONE); if (state == STATE_READY) { mFootTextView.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.GONE); mFootTextView.setText(R.string.pull_footer_hint_ready); } else if (state == STATE_LOADING) { mProgressBar.setVisibility(View.VISIBLE); mFootTextView.setVisibility(View.VISIBLE); } else { mFootTextView.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.GONE); mFootTextView.setText(R.string.pull_footer_hint_normal); } } public void setBottomMargin(int height) { if (height < 0) return ; LayoutParams lp = (LayoutParams)mContentView.getLayoutParams(); lp.bottomMargin = height; mContentView.setLayoutParams(lp); } public int getBottomMargin() { LayoutParams lp = (LayoutParams)mContentView.getLayoutParams(); return lp.bottomMargin; } public void normal() { mFootTextView.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.GONE); } public void loading() { mFootTextView.setVisibility(View.GONE); mProgressBar.setVisibility(View.VISIBLE); } public void hide() { LayoutParams lp = (LayoutParams)mContentView.getLayoutParams(); lp.height = 0; mContentView.setLayoutParams(lp); } public void show() { LayoutParams lp = (LayoutParams)mContentView.getLayoutParams(); lp.height = LayoutParams.WRAP_CONTENT; mContentView.setLayoutParams(lp); } private void initView(Context context) { mContext = context; LinearLayout moreView = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.layout_listview_footer, null); addView(moreView); moreView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); mContentView = moreView.findViewById(R.id.footer_view); mProgressBar = moreView.findViewById(R.id.footer_progressbar); mFootTextView = (TextView)moreView.findViewById(R.id.footer_textview); } public TextView getmFootTextView() { return mFootTextView; }}
然后我们通过继承自ListViwe实现一个下拉的PullListView类。
public class PullFreshListView extends ListView implements OnScrollListener { private float mLastY = -1; private Scroller mScroller; private OnScrollListener mScrollListener; private ListViewPlusListener mListViewListener; private boolean mPullRefreshing = false; private ListViewFooter mFooterView; private boolean mEnablePullLoad; private boolean mPullLoading; private boolean mIsFooterReady = false; private int mTotalItemCount; private int mScrollBack; private int minItemCount=3; private final static int SCROLLBACK_HEADER = 0; private final static int SCROLLBACK_FOOTER = 1; private final static int SCROLL_DURATION = 400; private final static int PULL_LOAD_MORE_DELTA = 50; private final static float OFFSET_RADIO = 1.8f; public PullFreshListView(Context context) { super(context); initWithContext(context); } public PullFreshListView(Context context, AttributeSet attrs) { super(context, attrs); initWithContext(context); } public PullFreshListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initWithContext(context); } private void initWithContext(Context context) { mScroller = new Scroller(context, new DecelerateInterpolator()); super.setOnScrollListener(this); mFooterView = new ListViewFooter(context); } @Override public void setAdapter(ListAdapter adapter) { if (mIsFooterReady == false) { mIsFooterReady = true; addFooterView(mFooterView); } super.setAdapter(adapter); } public void setLoadEnable(boolean enable) { mEnablePullLoad = enable; if (!mEnablePullLoad) { mFooterView.hide(); mFooterView.setOnClickListener(null); setFooterDividersEnabled(false); } else { mPullLoading = false; mFooterView.show(); mFooterView.setState(ListViewFooter.STATE_NORMAL); setFooterDividersEnabled(true); mFooterView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { startLoadMore(); } }); } } public void stopLoadMore() { if (mPullLoading == true) { mPullLoading = false; mFooterView.setState(ListViewFooter.STATE_NORMAL); } } private void invokeOnScrolling() { if (mScrollListener instanceof OnXScrollListener) { OnXScrollListener l = (OnXScrollListener) mScrollListener; l.onXScrolling(this); } } private void resetHeaderHeight() { invalidate(); } private void updateFooterHeight(float delta) { int height = mFooterView.getBottomMargin() + (int) delta; if (mEnablePullLoad && !mPullLoading) { if (height > PULL_LOAD_MORE_DELTA) { mFooterView.setState(ListViewFooter.STATE_READY); } else { mFooterView.setState(ListViewFooter.STATE_NORMAL); } } mFooterView.setBottomMargin(height); } private void resetFooterHeight() { int bottomMargin = mFooterView.getBottomMargin(); if (bottomMargin > 0) { mScrollBack = SCROLLBACK_FOOTER; mScroller.startScroll(0, bottomMargin, 0, -bottomMargin, SCROLL_DURATION); invalidate(); } } private void startLoadMore() { mPullLoading = true; mFooterView.setState(ListViewFooter.STATE_LOADING); if (mListViewListener != null) { mListViewListener.onLoadMore(); } } @Override public boolean onTouchEvent(MotionEvent ev) { if (mLastY == -1) { mLastY = ev.getRawY(); } switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mLastY = ev.getRawY(); break; case MotionEvent.ACTION_MOVE: final float deltaY = ev.getRawY() - mLastY; mLastY = ev.getRawY(); if (getLastVisiblePosition() == mTotalItemCount - 1 && (mFooterView.getBottomMargin() > 0 || deltaY < 0)) { updateFooterHeight(-deltaY / OFFSET_RADIO); } break; default: mLastY = -1; if (getFirstVisiblePosition() == 0) { resetHeaderHeight(); } else if (getLastVisiblePosition() == mTotalItemCount - 1) { if (mEnablePullLoad && mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA && !mPullLoading) { startLoadMore(); } resetFooterHeight(); } break; } return super.onTouchEvent(ev); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { if (mScrollBack == SCROLLBACK_HEADER) { } else { mFooterView.setBottomMargin(mScroller.getCurrY()); } postInvalidate(); invokeOnScrolling(); } super.computeScroll(); } @Override public void setOnScrollListener(OnScrollListener l) { mScrollListener = l; } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (mScrollListener != null) { mScrollListener.onScrollStateChanged(view, scrollState); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if(mFooterView!=null){ if (totalItemCount<minItemCount+2) { mFooterView.getmFootTextView().setText(""); }else { if(mFooterView.getmFootTextView().getText().toString().equals(""))mFooterView.getmFootTextView(). setText(getResources().getString(R.string.pull_footer_hint_normal)); } } mTotalItemCount = totalItemCount; if (mScrollListener != null) { mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); } } public void setListViewPlusListener(ListViewPlusListener l) { mListViewListener = l; } public interface OnXScrollListener extends OnScrollListener { void onXScrolling(View view); } public interface ListViewPlusListener { void onLoadMore(); }}
最后要实现可以悬浮的效果,我们需要对布局的滑动的数据进行监听,具体请看代码:
public class PullStickyListView extends PullFreshListView { public interface PinnedSectionListAdapter extends ListAdapter { boolean isItemViewTypePinned(int viewType); } static class PinnedSection { public View view; public int position; public long id; } private final Rect mTouchRect = new Rect(); private final PointF mTouchPoint = new PointF(); private int mTouchSlop; private View mTouchTarget; private MotionEvent mDownEvent; private GradientDrawable mShadowDrawable; private int mSectionsDistanceY; private int mShadowHeight; private OnScrollListener mDelegateOnScrollListener; private PinnedSection mRecycleSection; private PinnedSection mPinnedSection; private int mTranslateY; private final OnScrollListener mOnScrollListener = new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (mDelegateOnScrollListener != null) { mDelegateOnScrollListener.onScrollStateChanged(view, scrollState); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (mDelegateOnScrollListener != null) { mDelegateOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); } ListAdapter adapter = getAdapter(); if (adapter == null || visibleItemCount == 0) return; final boolean isFirstVisibleItemSection = isItemViewTypePinned(adapter, adapter.getItemViewType(firstVisibleItem)); if (isFirstVisibleItemSection) { View sectionView = getChildAt(0); if (sectionView.getTop() == getPaddingTop()) { destroyPinnedShadow(); } else { ensureShadowForPosition(firstVisibleItem, firstVisibleItem, visibleItemCount); } } else { int sectionPosition = findCurrentSectionPosition(firstVisibleItem); if (sectionPosition > -1) { ensureShadowForPosition(sectionPosition, firstVisibleItem, visibleItemCount); } else { destroyPinnedShadow(); } } } }; private final DataSetObserver mDataSetObserver = new DataSetObserver() { @Override public void onChanged() { recreatePinnedShadow(); } @Override public void onInvalidated() { recreatePinnedShadow(); } }; public PullStickyListView(Context context, AttributeSet attrs) { super(context, attrs); initView(); } public PullStickyListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initView(); } private void initView() { setOnScrollListener(mOnScrollListener); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();// initShadow(true); } public void setShadowVisible(boolean visible) { initShadow(visible); if (mPinnedSection != null) { View v = mPinnedSection.view; invalidate(v.getLeft(), v.getTop(), v.getRight(), v.getBottom() + mShadowHeight); } } public void initShadow(boolean visible) { if (visible) { if (mShadowDrawable == null) { mShadowDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, new int[]{Color.parseColor("#ffa0a0a0"), Color.parseColor("#50a0a0a0"), Color.parseColor("#00a0a0a0")}); mShadowHeight = (int) (8 * getResources().getDisplayMetrics().density); } } else { if (mShadowDrawable != null) { mShadowDrawable = null; mShadowHeight = 0; } } } void createPinnedShadow(int position) { PinnedSection pinnedShadow = mRecycleSection; mRecycleSection = null; if (pinnedShadow == null) pinnedShadow = new PinnedSection(); View pinnedView = getAdapter().getView(position, pinnedShadow.view, PullStickyListView.this); LayoutParams layoutParams = (LayoutParams) pinnedView.getLayoutParams(); if (layoutParams == null) { layoutParams = (LayoutParams) generateDefaultLayoutParams(); pinnedView.setLayoutParams(layoutParams); } int heightMode = MeasureSpec.getMode(layoutParams.height); int heightSize = MeasureSpec.getSize(layoutParams.height); if (heightMode == MeasureSpec.UNSPECIFIED) heightMode = MeasureSpec.EXACTLY; int maxHeight = getHeight() - getListPaddingTop() - getListPaddingBottom(); if (heightSize > maxHeight) heightSize = maxHeight; // measure & layout int ws = MeasureSpec.makeMeasureSpec(getWidth() - getListPaddingLeft() - getListPaddingRight(), MeasureSpec.EXACTLY); int hs = MeasureSpec.makeMeasureSpec(heightSize, heightMode); pinnedView.measure(ws, hs); pinnedView.layout(0, 0, pinnedView.getMeasuredWidth(), pinnedView.getMeasuredHeight()); mTranslateY = 0; // initialize pinned shadow pinnedShadow.view = pinnedView; pinnedShadow.position = position; pinnedShadow.id = getAdapter().getItemId(position); // store pinned shadow mPinnedSection = pinnedShadow; } void destroyPinnedShadow() { if (mPinnedSection != null) { mRecycleSection = mPinnedSection; mPinnedSection = null; } } void ensureShadowForPosition(int sectionPosition, int firstVisibleItem, int visibleItemCount) { if (visibleItemCount < 2) { destroyPinnedShadow(); return; } if (mPinnedSection != null && mPinnedSection.position != sectionPosition) { destroyPinnedShadow(); } if (mPinnedSection == null) { createPinnedShadow(sectionPosition); } int nextPosition = sectionPosition + 1; if (nextPosition < getCount()) { int nextSectionPosition = findFirstVisibleSectionPosition(nextPosition, visibleItemCount - (nextPosition - firstVisibleItem)); if (nextSectionPosition > -1) { View nextSectionView = getChildAt(nextSectionPosition - firstVisibleItem); final int bottom = mPinnedSection.view.getBottom() + getPaddingTop(); mSectionsDistanceY = nextSectionView.getTop() - bottom; if (mSectionsDistanceY < 0) { mTranslateY = mSectionsDistanceY; } else { mTranslateY = 0; } } else { mTranslateY = 0; mSectionsDistanceY = Integer.MAX_VALUE; } } } int findFirstVisibleSectionPosition(int firstVisibleItem, int visibleItemCount) { ListAdapter adapter = getAdapter(); int adapterDataCount = adapter.getCount(); if (getLastVisiblePosition() >= adapterDataCount) return -1; if (firstVisibleItem + visibleItemCount >= adapterDataCount) {//added to prevent index Outofbound (in case) visibleItemCount = adapterDataCount - firstVisibleItem; } for (int childIndex = 0; childIndex < visibleItemCount; childIndex++) { int position = firstVisibleItem + childIndex; int viewType = adapter.getItemViewType(position); if (isItemViewTypePinned(adapter, viewType)) return position; } return -1; } int findCurrentSectionPosition(int fromPosition) { ListAdapter adapter = getAdapter(); if (fromPosition >= adapter.getCount()) return -1; if (adapter instanceof SectionIndexer) { SectionIndexer indexer = (SectionIndexer) adapter; int sectionPosition = indexer.getSectionForPosition(fromPosition); int itemPosition = indexer.getPositionForSection(sectionPosition); int typeView = adapter.getItemViewType(itemPosition); if (isItemViewTypePinned(adapter, typeView)) { return itemPosition; } } for (int position = fromPosition; position >= 0; position--) { int viewType = adapter.getItemViewType(position); if (isItemViewTypePinned(adapter, viewType)) return position; } return -1; } void recreatePinnedShadow() { destroyPinnedShadow(); ListAdapter adapter = getAdapter(); if (adapter != null && adapter.getCount() > 0) { int firstVisiblePosition = getFirstVisiblePosition(); int sectionPosition = findCurrentSectionPosition(firstVisiblePosition); if (sectionPosition == -1) return; ensureShadowForPosition(sectionPosition, firstVisiblePosition, getLastVisiblePosition() - firstVisiblePosition); } } @Override public void setOnScrollListener(OnScrollListener listener) { if (listener == mOnScrollListener) { super.setOnScrollListener(listener); } else { mDelegateOnScrollListener = listener; } } @Override public void onRestoreInstanceState(Parcelable state) { super.onRestoreInstanceState(state); post(new Runnable() { @Override public void run() { recreatePinnedShadow(); } }); } @Override public void setAdapter(ListAdapter adapter) { if (adapter != null) { if (!(adapter instanceof PinnedSectionListAdapter)) throw new IllegalArgumentException("Does your adapter implement PinnedSectionListAdapter?"); if (adapter.getViewTypeCount() < 2) throw new IllegalArgumentException("Does your adapter handle at least two types" + " of views in getViewTypeCount() method: items and sections?"); } ListAdapter oldAdapter = getAdapter(); if (oldAdapter != null) oldAdapter.unregisterDataSetObserver(mDataSetObserver); if (adapter != null) adapter.registerDataSetObserver(mDataSetObserver); if (oldAdapter != adapter) destroyPinnedShadow(); super.setAdapter(adapter); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (mPinnedSection != null) { int parentWidth = r - l - getPaddingLeft() - getPaddingRight(); int shadowWidth = mPinnedSection.view.getWidth(); if (parentWidth != shadowWidth) { recreatePinnedShadow(); } } } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); if (mPinnedSection != null) { int pLeft = getListPaddingLeft(); int pTop = getListPaddingTop(); View view = mPinnedSection.view; canvas.save(); int clipHeight = view.getHeight() + (mShadowDrawable == null ? 0 : Math.min(mShadowHeight, mSectionsDistanceY)); canvas.clipRect(pLeft, pTop, pLeft + view.getWidth(), pTop + clipHeight); canvas.translate(pLeft, pTop + mTranslateY); drawChild(canvas, mPinnedSection.view, getDrawingTime()); if (mShadowDrawable != null && mSectionsDistanceY > 0) { mShadowDrawable.setBounds(mPinnedSection.view.getLeft(), mPinnedSection.view.getBottom(), mPinnedSection.view.getRight(), mPinnedSection.view.getBottom() + mShadowHeight); mShadowDrawable.draw(canvas); } canvas.restore(); } } @Override public boolean dispatchTouchEvent(MotionEvent ev) { final float x = ev.getX(); final float y = ev.getY(); final int action = ev.getAction(); if (action == MotionEvent.ACTION_DOWN && mTouchTarget == null && mPinnedSection != null && isPinnedViewTouched(mPinnedSection.view, x, y)) { mTouchTarget = mPinnedSection.view; mTouchPoint.x = x; mTouchPoint.y = y; mDownEvent = MotionEvent.obtain(ev); } if (mTouchTarget != null) { if (isPinnedViewTouched(mTouchTarget, x, y)) { mTouchTarget.dispatchTouchEvent(ev); } if (action == MotionEvent.ACTION_UP) { super.dispatchTouchEvent(ev); performPinnedItemClick(); clearTouchTarget(); } else if (action == MotionEvent.ACTION_CANCEL) { clearTouchTarget(); } else if (action == MotionEvent.ACTION_MOVE) { if (Math.abs(y - mTouchPoint.y) > mTouchSlop) { MotionEvent event = MotionEvent.obtain(ev); event.setAction(MotionEvent.ACTION_CANCEL); mTouchTarget.dispatchTouchEvent(event); event.recycle(); super.dispatchTouchEvent(mDownEvent); super.dispatchTouchEvent(ev); clearTouchTarget(); } } return true; } return super.dispatchTouchEvent(ev); } private boolean isPinnedViewTouched(View view, float x, float y) { view.getHitRect(mTouchRect); mTouchRect.top += mTranslateY; mTouchRect.bottom += mTranslateY + getPaddingTop(); mTouchRect.left += getPaddingLeft(); mTouchRect.right -= getPaddingRight(); return mTouchRect.contains((int) x, (int) y); } private void clearTouchTarget() { mTouchTarget = null; if (mDownEvent != null) { mDownEvent.recycle(); mDownEvent = null; } } private boolean performPinnedItemClick() { if (mPinnedSection == null) return false; OnItemClickListener listener = getOnItemClickListener(); if (listener != null && getAdapter().isEnabled(mPinnedSection.position)) { View view = mPinnedSection.view; playSoundEffect(SoundEffectConstants.CLICK); if (view != null) { view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); } listener.onItemClick(this, view, mPinnedSection.position, mPinnedSection.id); return true; } return false; } public static boolean isItemViewTypePinned(ListAdapter adapter, int viewType) { if (adapter instanceof HeaderViewListAdapter) { adapter = ((HeaderViewListAdapter) adapter).getWrappedAdapter(); } return ((PinnedSectionListAdapter) adapter).isItemViewTypePinned(viewType); }}
附:仿支付宝账单流水
饼状图:http://blog.csdn.net/kuangxiaoguo0123/article/details/53282809
0 0
- Android实现仿支付宝流水
- Android开发-仿支付宝支付密码EditText实现
- Android仿支付宝支付验证按钮
- Android仿支付宝淘宝
- Android仿支付宝淘宝
- Android实现支付宝支付
- Android实例-仿支付宝diaolog
- Android 仿支付宝设置app语言
- android 仿支付宝密码输入框
- Android仿支付宝九宫图效果
- Android (仿支付宝) 收益进度条
- Android 仿支付宝数字变换,滚动
- Android仿支付宝支付密码输入框
- Android仿支付宝支付密码输入框
- Android 仿支付宝支付密码输入框
- Android仿支付宝订单确认和支付
- Android数字动态显示,仿支付宝app效果简单的实现。字数从0-x!!!
- Android-仿支付宝手势密码(九宫格)简单实现-修复相关BUG
- 初步创建远程仓库,将本地仓库上传到git 远程仓库里
- centos7配置以及安装mysql5.7
- json字符串传到前台input
- 【3月17日】通过反射机制了解泛型的本质
- dojo框架简介
- Android实现仿支付宝流水
- 基于链表的词典
- hive2hive mtods自动设置权限实现
- 特殊的输入方式
- 判断网络连接是否已开 true 已打开 false 未打开
- Nvmain模拟器(单独使用)安装步骤:
- 路由器结构
- Redis大鹏博客转载____(一)Redis几种数据结构
- android获取bluetooth的信号强度(RSSI)