Android 中轴时光轴

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

Android 中轴时光轴的相关文章

【Android】时光轴效果

[Android]时光轴效果 支持平台:Android   运行环境:Eclipse   开发语言:Java 下载地址:http://t.cn/R71Ge5c 源码简介 利用ExpandableListView通过对布局的控制来实现时光轴效果,只要有点耐心,你,也可以~ 源码运行图

Android中轴旋转特效实现,制作别样的图片浏览器

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/10766017 Android API Demos中有很多非常Nice的例子,这些例子的代码都写的很出色,如果大家把API Demos中的每个例子研究透了,那么恭喜你已经成为一个真正的Android高手了.这也算是给一些比较迷茫的Android开发者一个指出了一个提升自我能力的方向吧.API Demos中的例子众多,今天我们就来模仿其中一个3D变换的特效,来实现一种别样的图片浏览器

Android高级图片滚动控件,编写3D版的图片轮播器

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17482089 大家好,好久不见了,最近由于工作特别繁忙,已经有一个多月的时间没写博客了,我也是深感惭愧.那么今天的这篇既然是阔别了一个多月的文章,当然要带来更加给力点的内容了,那么话不多说,赶快进入到今天的正题吧. 说 到图片轮播器,很多的Android应用中都会带有这个功能,比如说网易新闻.淘宝等.最新我们公司的一款应用也加入了这个功能,并且在图片轮播的基础上 还增加了三维立体

Android 3D滑动菜单完全解析,实现推拉门式的立体特效

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/10471245 在上一篇文章中,我们学习了Camera的基本用法,并借助它们编写了一个例子,实现了类似于API Demos里的图片中轴旋转功能.不过那个例子的核心代码是来自于API Demos中带有的Rotate3dAnimation这个类,是它帮助我们完成了所有的三维旋转操作,所有Matrix和Camera相关的代码也是封装在这个类中. 这样说来的话,大家心里会不会痒痒的呢?虽然

使用ExpandableListView实现一个时光轴

在许多App上都能看到时光轴的效果,比如携程等等,那么我们今天就利用ExpandableListView来实现一个时光轴效果,先来看看效果图: 效果还是挺简单的,这里我们主要是采用ExpandableListView来实现,关于ExpandableListView的详细使用参见(android开发之ExpandableListView的使用,实现类似QQ好友列表),我们这里主要介绍这个效果的实现: 先来看看主布局文件: <RelativeLayout xmlns:android="http

【Android】我的时光轴_0.9.9

自己需要就做了一个app 放到了各大市场,没有任何商业相关,做的也不够精细,给有需要的人 360:http://zhushou.360.cn/detail/index/soft_id/1716634 各大Android应用市场都有下载 [Android]我的时光轴_0.9.9

android源码大放送(实战开发必备),免费安卓demo源码,例子大全文件详细列表

免费安卓demo源码,例子大全文件详细列表 本列表源码永久免费下载地址:http://www.jiandaima.com/blog/android-demo 卷 yunpan 的文件夹 PATH 列表 卷序列号为 0000-73EC E:. │ jiandaima.com文件列表生成.bat │ 例子大全说明.txt │ 本例子永久更新地址~.url │ 目录列表2016.03.10更新.txt │ ├─前台界面 │ ├─3D标签云卡片热门 │ │ Android TagCloudView云标签

【转】Android应用开发之PNG、IconFont、SVG图标资源优化详解

1 背景 最近因为一些个人私事导致好久没写博客了,多事之年总算要过去了,突然没了动力,所以赶紧先拿个最近项目中重构的一个小知识点充下数,老题重谈. 在我们App开发中大家可能都会有过如下痛疾(程序员和设计妹妹注意喽): 好多小的图标好烦人,又占体积还要考虑分辨率,一拉伸就模糊等. 同一个图标不同状态还有不同颜色的多张. 总是幻想IOS.Android.Web等对于一个图标只切一次图多好. 如果你有过类似的痛疾那么下面讨论的故事就是一个完美的解决方案,当然了,采用下面方案对于重型应用或者固件级的优

Android动画三部曲之一 View Animation &amp; LayoutAnimation

转载请注明出处:http://blog.csdn.net/crazy1235/article/details/50612827 本篇文章对android的Tween动画和帧动画以及布局动画进行总结. Tween动画 XML语法介绍 插值器 Interpolator 自定义Interpolator 公共XML属性及对应的方法 ScaleAnimation 缩放动画 xml定义缩放动画 代码定义缩放动画 RotateAnimation 旋转动画 xml中设置旋转动画 代码中设置旋转动画 Transl