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 anymoreif (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"><ImageViewandroid: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" /><ImageViewandroid: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" /><ImageViewandroid: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"><ImageViewandroid: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" /><TextViewandroid: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" /><ImageViewandroid: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;}@Overridepublic int getItemViewType(int position) {return datas.get(position).getDtype().ordinal();}@Overridepublic 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() {@Overridepublic 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);}}});}@Overridepublic 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 中轴时光轴相关推荐

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

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/10471245 在上一篇文章中,我们学习了Camera的基本用法,并借助它们编写了一 ...

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

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17482089 大家好,好久不见了,最近由于工作特别繁忙,已经有一个多月的时间没写博 ...

  3. Android 常用开发功能 博客导航

    转载地址:http://blog.csdn.net/ciqing123/article/details/52931663?locationNum=16&fps=1 简介:第一次在CSDN上发表 ...

  4. 使用ExpandableListView实现一个时光轴

    在许多App上都能看到时光轴的效果,比如携程等等,那么我们今天就利用ExpandableListView来实现一个时光轴效果,先来看看效果图: 效果还是挺简单的,这里我们主要是采用Expandable ...

  5. androidd时光轴效果实现

    一个好的应用肯定有一个好看的界面,给自己界面增加各种各样的特效或者独树一帜的外观,即使功能差不多,但你的应用肯定更受欢迎, 给应用加特效一般会写很多xml文件作为控件的背景,这种方式很容易实现,也很简 ...

  6. 搜集整理的一些博客导航

    简介:第一次在CSDN上发表博客,将自己关注或者看过的一些博客整理了一下,其中包含了鸿神和郭神的全部博客,包括两位大神微信公众号推荐的博客,另外还有一些安卓开发社区的博客,后续每天都会更新这个导航,希 ...

  7. 轴旋转——制作别样的图片浏览器

    首页 博客 学院 下载 GitChat TinyMind 论坛 问答 商城 VIP 活动 招聘 ITeye CSTO 写博客 发Chat 贵公子丶笔记 千里之行,始于足下. RSS订阅 转 Andro ...

  8. 【压岁干货】精彩技术博客+优秀源码集锦

    虽然2015年已经过了一月有余,但在中国,好像只有过了春节才算进入新的一年.眼看着这也春节倒计时了,大家好像又都忙了起来,赶项目赶项目-- 从DevStore整理了一些优秀的技术博客和源码作为新春贺礼 ...

  9. Android之RecyclerView实现时光轴

    做项目的过程中有个需求需要时光轴,于是网上找了部分资料 ,写了个案例,现在分享给大家. 如图: activity_main.xml <?xml version="1.0" e ...

  10. Android 时光轴 -记录生活

    /** *  * 转载请标明出处:http://blog.csdn.net/u013598111/article/details/50519404 *   @author:[JunTao_sun]   ...

最新文章

  1. 两条波浪线符号_四年级数学上册第二单元“线的认识”作业单(附带答案)
  2. 【机器学习】libsvm使用的数据格式
  3. 城市轨道交通运营票务管理论文_城市轨道交通票务组织管理论文
  4. sklearn线性回归
  5. Android之录音--AudioRecord、MediaRecorder
  6. ORACLE中表死锁的处理
  7. linux7自动挂载怎么做,CentOS7 Virtual Box 开机自动挂载共享文件夹
  8. 数据库实验6 数据库的分组查询和统计查询
  9. Linux 如何限制用户的磁盘使用量 -- quota
  10. 20200627每日一句
  11. Mybatis源码深度解析
  12. 数据统计分析(SPSS)【8】
  13. 用uniapp做的一个在线简历,可以发布成为微信小程序,给面试加分
  14. ShareX(截图工具) 绿色版,功能异常强大
  15. python的cubes怎么使用_Python measure.marching_cubes方法代碼示例
  16. 采集新闻数据的10个经典方法
  17. ps2015安装guideguide参考线辅助工具
  18. SpringMVC之405错误码
  19. Android布局优化
  20. 都说在阿里年薪百万不难,面试入职阿里需要准备什么?

热门文章

  1. 计算机ps图片在哪里看,怎么看图片有没有PS 两种查看照片有没被PS过的方法-电脑教程...
  2. 油猴插件安装以及好用的脚本推荐
  3. windows10搜索卡死(有出现Cortana的请看这篇文章)
  4. 视频编解码(一):ffmpeg编码H.264帧类型判断
  5. Mac Spotlight 聚焦搜索
  6. WinEdit编辑器中中文乱码
  7. 解决 winedit 打开tex文件 reading error
  8. 物联网安全风险威胁报告
  9. 封装jquery的方法
  10. The server time zone value '?й???????' is unrecognized or represents more than one time zone.