美文网首页Android开发Android技术知识Android开发经验谈
关于实现RecyclerView之FooterView的一种新设

关于实现RecyclerView之FooterView的一种新设

作者: meStronger | 来源:发表于2018-08-16 19:38 被阅读35次

    FooterView

    实现FooterView的一种新思路,当FooterView距离屏幕顶部不超过一屏高度会自动消失。

    RecyclerView添加FooterView 的方法很多,但是产品经理的需求又来了,他说:“这个FooterView在列表不满一屏的时候不显示。” 怕是躲不掉了,一辈子都不可能躲得掉的,那就乖乖实现咯。

    先上代码(Feel free to copy):

    
    public class FooterView extends FrameLayout {
    
       public FooterView(@NonNull Context context) {
           super(context);
       }
    
       public FooterView(@NonNull Context context, @Nullable AttributeSet attrs) {
           super(context, attrs);
       }
    
       public FooterView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
           super(context, attrs, defStyleAttr);
       }
    
       @Override
       protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
           super.onLayout(changed, left, top, right, bottom);
           View child = getChildAt(0);
           if (child != null) {
               int heightPixels = getContext().getResources().getDisplayMetrics().heightPixels;
               int rawY = heightPixels - getRawTop(getParent());
               if (rawY > 0 && top > rawY) {//FooterView的顶部距离屏幕顶部超过一屏高度
                   getChildAt(0).setVisibility(VISIBLE);
               } else {
                   getChildAt(0).setVisibility(GONE);
               }
           }
       }
    
       //获取与屏幕顶部的距离
       private int getRawTop(ViewParent parent) {
           if (parent == null || ((ViewGroup) parent).getId() == Window.ID_ANDROID_CONTENT) {
               if (parent != null) {
                   int[] position = new int[2];
                   ((ViewGroup) parent).getLocationOnScreen(position);
                   return position[1];
               }
               return 0;
           } else {
               return ((ViewGroup) parent).getTop() + getRawTop(parent.getParent());
           }
       }
    
       @Override
       public void addView(View child) {
           if (getChildCount() > 0) {//限制只能添加一个子View
               throw new IllegalStateException("FooterView can host only one direct child");
           }
    
           super.addView(child);
       }
    
    }
    

    怎么用?

    放在RecyclerView下方即可:

    <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical">
    
       <android.support.v7.widget.RecyclerView
           android:id="@+id/recyclerView"
           android:layout_width="match_parent"
           android:layout_height="wrap_content" />
    
       <org.salient.autofooter.FooterView
           android:layout_width="match_parent"
           android:layout_height="wrap_content">
    
           <include layout="@layout/layout_footer"/>
    
       </org.salient.autofooter.FooterView>
    
    </LinearLayout>
    

    Note: FooterView继承于FramLayout,本身不带视图,可以像上面的例子一样,在xml布局中加入视图,或者调用FooterView.addView(View child)添加视图,需要注意的是,FooterView只能添加一个直属子View。

    简单讲一下实现思路

    要实现RecyclerView不满一屏不显示FooterView,关键在于如何知道RecyclerView不满一屏,当然RecyclerView上边还有ActionBarToolbar,状态栏等等,如果仅仅去比较RecyclerView的高度和屏幕高度,显然不可行。因此,产品经理心里想要的效果应当是应当是RecyclerView和状态栏等加起来铺不满一屏的时候,FooterView就不显示。

    如果用传统的方式,需要把FooterView作为RecyclerView的一个Item去处理,并且把状态栏等高度考虑进去,以决定FooterView的是否显示内容。

    这里尝试用一种新的方式去实现,就是让FooterView放在RecyclerView的下面,根据自己的位置自行决定要不要显示。实现步骤:
    • 1.新建一个类FooterView.class,让它继承自FramLayout
    public class FooterView extends FrameLayout {
    
       public FooterView(@NonNull Context context) {
           super(context);
       }
    
       public FooterView(@NonNull Context context, @Nullable AttributeSet attrs) {
           super(context, attrs);
       }
    
       public FooterView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
           super(context, attrs, defStyleAttr);
       }
    }
    
    
    • 2.重写onLayout()方法,在FooterView添加到布局或者布局发生变动时判断是否显示内容。
       @Override
       protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
           super.onLayout(changed, left, top, right, bottom);
           View child = getChildAt(0);
           if (child != null) {
               int heightPixels = getContext().getResources().getDisplayMetrics().heightPixels;
               int rawY = heightPixels - getRawTop(getParent());
               if (rawY > 0 && top > rawY) {//FooterView的顶部距离屏幕顶部超过一屏高度
                   getChildAt(0).setVisibility(VISIBLE);
               } else {
                   getChildAt(0).setVisibility(GONE);
               }
           }
       }
    
    • 3.利用递归获取与屏幕顶部的距离。
       //获取与屏幕顶部的距离
       private int getRawTop(ViewParent parent) {
           if (parent == null || ((ViewGroup) parent).getId() == Window.ID_ANDROID_CONTENT) {
               if (parent != null) {
                   int[] position = new int[2];
                   ((ViewGroup) parent).getLocationOnScreen(position);
                   return position[1];
               }
               return 0;
           } else {
               return ((ViewGroup) parent).getTop() + getRawTop(parent.getParent());
           }
       }
    

    最后附上GIthub地址:

    https://github.com/maiwenchang/FooterView

    Welcome star~~

    相关文章

      网友评论

        本文标题:关于实现RecyclerView之FooterView的一种新设

        本文链接:https://www.haomeiwen.com/subject/ssjnbftx.html