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的可见位置。

    • 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方法实现的有点丑陋,并且影响了效率,如果你有更好的欢迎留言建议。

更多相关文章

  1. Android(安卓)shape属性详细整理
  2. Android中TextView控件的singleLine废弃解决
  3. android圆角ImageView的几种实现方式
  4. android ListView美化-->几个比较特别的属性
  5. Android的四大组件之三--Activity(4)----->Activity的启动方式和相
  6. Android动态修改APP图标
  7. 图解 Android(安卓)事件分发机制
  8. Android(安卓)如何禁止屏幕灭屏
  9. Android中网络传输不同内容

随机推荐

  1. Android图片轮播
  2. Android遍历获取指定目录的文件
  3. ListView与其中的Button,EditText等Widge
  4. 在ubuntu10.10上安装android sdk
  5. error:Error parsing XML:unbound prefix
  6. android开发数据存储方式
  7. android ListView的属性
  8. 【android】查看应用签名信息
  9. Android(安卓)WindowManager$BadTokenExc
  10. Android------Intent