[置顶] Android(安卓)中轴时光轴
Android 中轴时光轴
ps:好久都没有写博客了,今天正好比较空,就来写一篇,好像这才是第二篇,不过不要在意这些细节啦。
转载请注明出处:http://blog.csdn.net/qq_15736263/article/details/51941066
效果图
:
美女图片都是 熊(百)掌(度)找的,如果有涉及到您的权益,请及时联系我进行删除。
就是这样的效果,这张图片因为某些原因,已经经过ps修改,请见谅我ps功底差!
第二个Item因为需要,固定添加了paddingTop。
一些说明
刚开始在网上找这种效果的实现,也在论坛上提过问。都没有能解决问题。
其实瀑布流是很好实现的。主要是中间圆点让人十分蛋疼。
最开始有考虑过几种解决方式
使用网络上开源的瀑布流控件,然后进行重写:
发现都是用使用GridView或者是ListView或者ViewGroup实现的,使用的都是类似LinnearLayout的布局方式,修改起来比较困难,牵扯面较多,然后放弃了。
使用RecyclerView然后自定义LayoutManager:
其实这个是最好的实现方式,但是因为时间太赶,加上网络上相关资源太少。只好去参考官方StaggeredGridLayoutManager了。
然后就源码旅游了。
@Overridepublic void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { onLayoutChildren(recycler, state, true);} private void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state, boolean shouldCheckForGaps) { final AnchorInfo anchorInfo = mAnchorInfo; anchorInfo.reset(); if (mPendingSavedState != null || mPendingScrollPosition != NO_POSITION) { if (state.getItemCount() == 0) { removeAndRecycleAllViews(recycler); return; } } if (mPendingSavedState != null) { applyPendingSavedState(anchorInfo); } else { resolveShouldLayoutReverse(); anchorInfo.mLayoutFromEnd = mShouldReverseLayout; } updateAnchorInfoForLayout(state, anchorInfo); if (mPendingSavedState == null) { if (anchorInfo.mLayoutFromEnd != mLastLayoutFromEnd || isLayoutRTL() != mLastLayoutRTL) { mLazySpanLookup.clear(); anchorInfo.mInvalidateOffsets = true; } } if (getChildCount() > 0 && (mPendingSavedState == null || mPendingSavedState.mSpanOffsetsSize < 1)) { if (anchorInfo.mInvalidateOffsets) { for (int i = 0; i < mSpanCount; i++) { // Scroll to position is set, clear. mSpans[i].clear(); if (anchorInfo.mOffset != INVALID_OFFSET) { mSpans[i].setLine(anchorInfo.mOffset); } } } else { for (int i = 0; i < mSpanCount; i++) { mSpans[i].cacheReferenceLineAndClear(mShouldReverseLayout, anchorInfo.mOffset); } } } detachAndScrapAttachedViews(recycler); mLayoutState.mRecycle = false; mLaidOutInvalidFullSpan = false; updateMeasureSpecs(mSecondaryOrientation.getTotalSpace()); updateLayoutState(anchorInfo.mPosition, state); if (anchorInfo.mLayoutFromEnd) { // Layout start. setLayoutStateDirection(LAYOUT_START); fill(recycler, mLayoutState, state); // Layout end. setLayoutStateDirection(LAYOUT_END); mLayoutState.mCurrentPosition = anchorInfo.mPosition + mLayoutState.mItemDirection; fill(recycler, mLayoutState, state); } else { // Layout end. setLayoutStateDirection(LAYOUT_END); fill(recycler, mLayoutState, state); // Layout start. setLayoutStateDirection(LAYOUT_START); mLayoutState.mCurrentPosition = anchorInfo.mPosition + mLayoutState.mItemDirection; fill(recycler, mLayoutState, state); } repositionToWrapContentIfNecessary(); if (getChildCount() > 0) { if (mShouldReverseLayout) { fixEndGap(recycler, state, true); fixStartGap(recycler, state, false); } else { fixStartGap(recycler, state, true); fixEndGap(recycler, state, false); } } boolean hasGaps = false; if (shouldCheckForGaps && !state.isPreLayout()) { final boolean needToCheckForGaps = mGapStrategy != GAP_HANDLING_NONE && getChildCount() > 0 && (mLaidOutInvalidFullSpan || hasGapsToFix() != null); if (needToCheckForGaps) { removeCallbacks(mCheckForGapsRunnable); if (checkForGaps()) { hasGaps = true; } } mPendingScrollPosition = NO_POSITION; mPendingScrollPositionOffset = INVALID_OFFSET; } mLastLayoutFromEnd = anchorInfo.mLayoutFromEnd; mLastLayoutRTL = isLayoutRTL(); mPendingSavedState = null; // we don't need this anymore if (hasGaps) { onLayoutChildren(recycler, state, false); }}
这里牵扯的东西非常多,因为StaggeredGridLayoutManager不单单考虑两列的情况。这个类的代码量在3000行,牵扯的到的同包的类也很多,这么算下来,代码量就远远不止3000行了,得需要点时间进行研究了。但是真的时间太赶了,只能另寻它路了。ps:加上水平有点烂啦。
我的实现方式:
- 简述:
因为上面的各种问题,主要是项目时间不够,想想用low的方法好了。直接用RecyclerView和StaggeredGridLayoutManager实现他,在onBindViewHolder用ViewHolder.post(Runnable) 在顶层用RelativeLayout动态添加View,并且绑定RecyclerView的滑动监听,进行滑动管理,自己进行维护生成的View的各种状态,包括进行缓存。但是这种效率真的是太低了,而且滑动的View复用处理不好的话,很容易就添加了N个圆点,只是不在屏幕内而且,而且这么写,圆点基本上就只能做成一种。项目中又需要不止一种类的圆点,存在一种年份的Item,和正常的Item带箭头的、颜色、大小都不一样的。
后来想起来一个神奇的属性,这个属性经常被人遗忘,因为他确实用的不多,但是确实好用。‘android:clipChildren=”false”’与之相配套的是’ android:clipToPadding=”false”’关于这两个属性这里就不多做介绍了,相关效果请自行熊(百)掌(度)。 代码:
XML布局:
- Activity/Fragment:
<FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="#DDD" android:clipChildren="false" android:clipToPadding="false"> <View android:layout_width="1dp" android:layout_height="match_parent" android:layout_gravity="center_horizontal" android:background="#DFDAD7" /> <android.support.v7.widget.RecyclerView android:id="@+id/view1" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="false" /></FrameLayout>
这里在在FrameLayout和RecyclerView上添加android:clipChildren=”false”属性是很有必要的,不然Item中的效果可能发挥不出来。
Item:
标准Item:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:clipChildren="false"android:clipToPadding="false"android:orientation="horizontal"><ImageView android:id="@+id/view1" android:layout_width="30dp" android:layout_height="20dp" android:layout_marginLeft="@dimen/_dp8" android:layout_marginTop="30dp" android:clipChildren="false" android:clipToPadding="false" android:contentDescription="@string/app_name" android:src="@mipmap/right" /><ImageView android:id="@+id/view3" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/dp10" android:layout_marginTop="@dimen/dp10" android:layout_weight="1" android:background="@drawable/progress_dialog" android:contentDescription="@string/app_name" android:scaleType="fitCenter" /><ImageView android:id="@+id/view2" android:layout_width="30dp" android:layout_height="20dp" android:layout_marginRight="@dimen/_dp8" android:layout_marginTop="30dp" android:clipChildren="false" android:clipToPadding="false" android:contentDescription="@string/app_name" android:src="@mipmap/letf" /></LinearLayout>
YearItem:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:clipChildren="false"android:clipToPadding="false"android:paddingBottom="@dimen/dp10"android:paddingTop="@dimen/dp10"><ImageView android:id="@id/view1" android:layout_width="20dp" android:layout_height="20dp" android:layout_gravity="left" android:layout_marginLeft="-10dp" android:clipChildren="false" android:clipToPadding="false" android:contentDescription="@string/app_name" android:src="@mipmap/year" /><TextView android:id="@id/textV1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:layout_marginRight="30dp" android:background="@drawable/year" android:gravity="center" android:minHeight="20dp" android:paddingBottom="5dp" android:paddingLeft="20dp" android:paddingRight="20dp" android:paddingTop="5dp" android:textColor="@color/colorPrimary" /><ImageView android:id="@id/view2" android:layout_width="20dp" android:layout_height="20dp" android:layout_gravity="right" android:layout_marginRight="-10dp" android:clipChildren="false" android:clipToPadding="false" android:contentDescription="@string/app_name" android:src="@mipmap/year" /></FrameLayout>
这里的view1和View2代表了左右两个箭头及圆点。中间的View3可以替换成任意的View(Layout也行),@dimen/_dp8是-8dp,让View位置超出父View的可见位置。
- Activity/Fragment:
Java:
Activity/Fragment:
public class Activity_Fragment { private RecyclerView mRecyclerView; private Adapter mAdapter; onCreate/onCreateView(){ mRecyclerView = (RecyclerView) rootView.findViewById(R.id.view1); mRecyclerView.setAdapter(adapter); StaggeredGridLayoutManager df = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); df.invalidateSpanAssignments(); //↑↑↑这里很重要,不然Item会自动换位置,会导致圆圈和箭头的方向不对 mRecyclerView.setLayoutManager(df); mAdapter= new Adapter(Context,List); mRecyclerView.setAdaper(mAdapter); } }
Adapter:
public class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private LayoutInflater mInflater; private final ArrayList<Data> datas; public BigEventAdapter(Context mCtx, ArrayList<Data> dataList) { super(); mInflater = LayoutInflater.from(mCtx); this.datas= dataList; } @Override public int getItemViewType(int position) { return datas.get(position).getDtype().ordinal(); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewgroup, int viewType) { if (type == DTYPE.ITEM.ordinal()) { rootView = mInflater.inflate(R.layout.view_item_add, viewgroup, false); return new ItemViewHolder(rootView); } if (type == DTYPE.YEAR.ordinal()) { rootView = mInflater.inflate(R.layout.view_item_year, viewgroup, false); return new TextViewHolder(rootView); } } /** * 判读左右显示相应的圆圈及箭头 */ private void isLeftOfRight(final CardViewHolder viewHolder) { ((ViewGroup) viewHolder.itemView).setClipChildren(false); viewHolder.itemView.post(new Runnable() { @Override public void run() { int left = viewHolder.itemView.getLeft(); if (left == 0) { viewHolder.itemArrow_Left.setVisibility(View.VISIBLE); viewHolder.itemArrow_Right.setVisibility(View.INVISIBLE); if (viewHolder.itemView instanceof FrameLayout) { FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) ((FrameLayout) viewHolder.itemView).getChildAt(1).getLayoutParams(); params.gravity = Gravity.RIGHT; ((FrameLayout) viewHolder.itemView).getChildAt(1).setLayoutParams(params); } } else { if (viewHolder.itemView instanceof FrameLayout) { FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) ((FrameLayout) viewHolder.itemView).getChildAt(1).getLayoutParams(); params.gravity = Gravity.LEFT; ((FrameLayout) viewHolder.itemView).getChildAt(1).setLayoutParams(params); } viewHolder.itemArrow_Left.setVisibility(View.INVISIBLE); viewHolder.itemArrow_Right.setVisibility(View.VISIBLE); } } }); } @Override public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { isLeftOfRight((CardViewHolder) viewHolder); ...... } public class CardViewHolder extends RecyclerView.ViewHolder { public ImageView itemArrow_Left; public ImageView itemArrow_Right; CardViewHolder(View layout) { super(layout); itemArrow_Left = (ImageView) layout.findViewById(R.id.view2); itemArrow_Right = (ImageView) layout.findViewById(R.id.view1); } } public class ItemViewHolder extends CardViewHolder { public ImageView icon; ItemViewHolder (View layout) { super(layout); icon = (ImageView) layout.findViewById(R.id.view3); } } public class TextViewHolder extends CardViewHolder { public TextView time; TextViewHolder(View layout) { super(layout); time = (TextView) layout.findViewById(R.id.textV1); } } }
Data.getDtype获取到的是一个枚举类型现在唯一的问题是isLeftOfRight方法实现的有点丑陋,并且影响了效率,如果你有更好的欢迎留言建议。
更多相关文章
- Android(安卓)shape属性详细整理
- Android中TextView控件的singleLine废弃解决
- android圆角ImageView的几种实现方式
- android ListView美化-->几个比较特别的属性
- Android的四大组件之三--Activity(4)----->Activity的启动方式和相
- Android动态修改APP图标
- 图解 Android(安卓)事件分发机制
- Android(安卓)如何禁止屏幕灭屏
- Android中网络传输不同内容