码迷,mamicode.com
首页 > 移动开发 > 详细

Android 中轴时光轴

时间:2016-07-19 10:09:19      阅读:250      评论:0      收藏:0      [点我收藏+]

标签:

Android 中轴时光轴

ps:好久都没有写博客了,今天正好比较空,就来写一篇,好像这才是第二篇,不过不要在意这些细节啦。

转载请注明出处:http://blog.csdn.net/qq_15736263/article/details/51941066

效果图

技术分享
美女图片都是 熊(百)掌(度)找的,如果有涉及到您的权益,请及时联系我进行删除。
就是这样的效果,这张图片因为某些原因,已经经过ps修改,请见谅我ps功底差!
第二个Item因为需要,固定添加了paddingTop。

一些说明

刚开始在网上找这种效果的实现,也在论坛上提过问。都没有能解决问题。
其实瀑布流是很好实现的。主要是中间圆点让人十分蛋疼。

最开始有考虑过几种解决方式

使用网络上开源的瀑布流控件,然后进行重写:

发现都是用使用GridView或者是ListView或者ViewGroup实现的,使用的都是类似LinnearLayout的布局方式,修改起来比较困难,牵扯面较多,然后放弃了。

使用RecyclerView然后自定义LayoutManager:

其实这个是最好的实现方式,但是因为时间太赶,加上网络上相关资源太少。只好去参考官方StaggeredGridLayoutManager了。
然后就源码旅游了。

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

Android 中轴时光轴

标签:

原文地址:http://blog.csdn.net/qq_15736263/article/details/51941066

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!