Home>

Recently the project intends to make an interface,Similar to the interface effect of the dayone homepage,dayone is a paid app,Currently only the ios side. As a senior lazy programmer,The purpose is to never build a wheel.So, go online to find a lot of open source projects,Found no suitable ones,Then, I had to bite the bullet and came by myself.First look at the effect:

Effect map

In fact, it is relatively simple to write,Just control the height of the head and bottom of the listview. If you use recycleview to achieve the same,It's just a little more troublesome to add a head and tail to recycleview,Handling click events is not very convenient,So it is implemented based on listview.Implemented code, I have uploaded it on github.

1.How to use

compile "com.a520wcf.yllistview:yllistview:1.0.1

2.Introduction to use:

1) Layout:

Layout pay attention to a small detail android:layout_height is best to match_parent, otherwise the listview may need to recalculate the height of the item each time it slidesMore costly cpu;

<com.a520wcf.yllistview.yllistview
 android:divider="@ android:color/transparent"
 android:id="@ + id/listview"
 android:layout_width="match_parent"
 android:layout_height="match_parent" />

2) Code:

private yllistview listview;
 @override
 protected void oncreate (bundle savedinstancestate) {
  super.oncreate (savedinstancestate);
  setcontentview (r.layout.activity_main);
  listview=(yllistview) findviewbyid (r.id.listview);
  //don't add and have default head and bottom
  view topview=view.inflate (this, r.layout.top, null);
  listview.addheaderview (topview);
  view bottomview=new view (getapplicationcontext ());
  listview.addfooterview (bottomview);
  //The top and bottom can also fix the final height.If not fixed, use the height of the layout itself.
  listview.setfinalbottomheight (100);
  listview.setfinaltopheight (100);
  listview.setadapter (new demoadapter ());
  //yllistview has head and bottom by default.
  listview.setonitemclicklistener (new adapterview.onitemclicklistener () {
   @override
   public void onitemclick (adapterview<?>parent, view view, int position, long id) {
    position=position-listview.getheaderviewscount ();
   }
  });
 }

3.Source code introductionIn fact, there is only one class in this project.You don't need to rely on it,Just copy this class into the project,Take a look at the source code:

package com.a520wcf.yllistview;
import android.content.context;
import android.util.attributeset;
import android.view.motionevent;
import android.view.view;
import android.view.viewtreeobserver.ongloballayoutlistener;
import android.view.animation.decelerateinterpolator;
import android.widget.abslistview;
import android.widget.listview;
import android.widget.scroller;
public class yllistview extends listview implements abslistview.onscrolllistener {
 private scroller mscroller;//used for scroll back
 private float mlasty=-1;
 private int mscrollback;
 private final static int scrollback_header=0;
 private final static int scrollback_footer=1;
 private final static int scroll_duration=400;//scroll back duration
 private final static float offset_radio=1.8f;
 //total list items, used to detect is at the bottom of listview.
 private int mtotalitemcount;
 private view mheaderview;//top image
 private view mfooterview;//bottom image
 private int finaltopheight;
 private int finalbottomheight;
 public yllistview (context context) {
  super (context);
  initwithcontext (context);
 }
 public yllistview (context context, attributeset attrs) {
  super (context, attrs);
  initwithcontext (context);
 }
 public yllistview (context context, attributeset attrs, int defstyle) {
  super (context, attrs, defstyle);
  initwithcontext (context);
 }
 private void initwithcontext (context context) {
  mscroller=new scroller (context, new decelerateinterpolator ());
  super.setonscrolllistener (this);
  this.getviewtreeobserver (). addongloballayoutlistener (
    new ongloballayoutlistener () {
     @override
     public void ongloballayout () {
      if (mheaderview == null) {
       view view=new view (getcontext ());
       addheaderview (view);
      }
      if (mfooterview == null) {
       view view=new view (getcontext ());
       addfooterview (view);
      }
      getviewtreeobserver ()
        .removeglobalonlayoutlistener (this);
     }
    });
 }
 @override
 public boolean ontouchevent (motionevent ev) {
  if (mlasty == -1) {
   mlasty=ev.getrawy ();
  }
  switch (ev.getaction ()) {
   case motionevent.action_down:
    mlasty=ev.getrawy ();
    break;
   case motionevent.action_move:
    final float deltay=ev.getrawy ()-mlasty;
    mlasty=ev.getrawy ();
    if (getfirstvisibleposition () == 0&&(mheaderview.getheight ()>finaltopheight || deltay>0)
      &&mheaderview.gettop ()>= 0) {
     //the first item is showing, header has shown or pull down.
     updateheaderheight (deltay/offset_radio);
    } else if (getlastvisibleposition () == mtotalitemcount-1
      &&(getfootheight ()>finalbottomheight || deltay<0)) {
     updatefooterheight (-deltay/offset_radio);
    }
    break;
   default:
    mlasty=-1;//reset
    if (getfirstvisibleposition () == 0&&getheaderheight ()>finaltopheight) {
     resetheaderheight ();
    }
    if (getlastvisibleposition () == mtotalitemcount-1) {
      if (getfootheight ()>finalbottomheight) {
       resetfooterheight ();
      }
    }
    break;
  }
  return super.ontouchevent (ev);
 }
 /**
  * Reset bottom height
  * /
 private void resetfooterheight () {
  int bottomheight=getfootheight ();
  if (bottomheight>finalbottomheight) {
   mscrollback=scrollback_footer;
   mscroller.startscroll (0, bottomheight, 0, -bottomheight + finalbottomheight,     scroll_duration);
   invalidate ();
  }
 }
 //Calculate the slippage When invalidate () is called
 @override
 public void computescroll () {
  if (mscroller.computescrolloffset ()) {
   if (mscrollback == scrollback_header) {
    setheaderheight (mscroller.getcurry ());
   } else {
    setfooterviewheight (mscroller.getcurry ());
   }
   postinvalidate ();
  }
  super.computescroll ();
 }
 //set the top height
 private void setheaderheight (int height) {
  layoutparams layoutparams=(layoutparams) mheaderview.getlayoutparams ();
  layoutparams.height=height;
  mheaderview.setlayoutparams (layoutparams);
 }
 //set the bottom height
 private void setfooterviewheight (int height) {
  layoutparams layoutparams =
    (layoutparams) mfooterview.getlayoutparams ();
  layoutparams.height=height;
  mfooterview.setlayoutparams (layoutparams);
 }
 //Get the top height
 public int getheaderheight () {
  abslistview.layoutparams layoutparams =
    (abslistview.layoutparams) mheaderview.getlayoutparams ();
  return layoutparams.height;
 }
 //Get the bottom height
 public int getfootheight () {
  abslistview.layoutparams layoutparams =
    (abslistview.layoutparams) mfooterview.getlayoutparams ();
  return layoutparams.height;
 }
 private void resetheaderheight () {
  int height=getheaderheight ();
  if (height == 0) //not visible.
   return;
  mscrollback=scrollback_header;
  mscroller.startscroll (0, height, 0, finaltopheight-height,    scroll_duration);
  invalidate ();
 }
 /**
  * Set the top height If you do not set the height,The default is the height of the layout itself
  * @param height top height
  * /
 public void setfinaltopheight (int height) {
  this.finaltopheight=height;
 }
 /**
  * Set the bottom height If you do not set the height,The default is the height of the layout itself
  * @param height bottom height
  * /
 public void setfinalbottomheight (int height) {
  this.finalbottomheight=height;
 }
 @override
 public void addheaderview (view v) {
  mheaderview=v;
  super.addheaderview (mheaderview);
  mheaderview.getviewtreeobserver (). addongloballayoutlistener (
    new ongloballayoutlistener () {
     @override
     public void ongloballayout () {
      if (finaltopheight == 0) {
       finaltopheight=mheaderview.getmeasuredheight ();
      }
      setheaderheight (finaltopheight);
      getviewtreeobserver ()
        .removeglobalonlayoutlistener (this);
     }
    });
 }
 @override
 public void addfooterview (view v) {
  mfooterview=v;
  super.addfooterview (mfooterview);
  mfooterview.getviewtreeobserver (). addongloballayoutlistener (
    new ongloballayoutlistener () {
     @override
     public void ongloballayout () {
      if (finalbottomheight == 0) {
       finalbottomheight=mfooterview.getmeasuredheight ();
      }
      setfooterviewheight (finalbottomheight);
      getviewtreeobserver ()
        .removeglobalonlayoutlistener (this);
     }
    });
 }
 private onscrolllistener mscrolllistener;//user "s scroll listener
 @override
 public void setonscrolllistener (onscrolllistener l) {
  mscrolllistener=l;
 }
 @override
 public void onscrollstatechanged (abslistview view, int scrollstate) {
  if (mscrolllistener!=null) {
   mscrolllistener.onscrollstatechanged (view, scrollstate);
  }
 }
 @override
 public void onscroll (abslistview view, int firstvisibleitem,       int visibleitemcount, int totalitemcount) {
  //send to user "s listener
  mtotalitemcount=totalitemcount;
  if (mscrolllistener!=null) {
   mscrolllistener.onscroll (view, firstvisibleitem, visibleitemcount,     totalitemcount);
  }
 }
 private void updateheaderheight (float delta) {
  setheaderheight ((int) (getheaderheight () + delta));
  setselection (0);//scroll to top each time
 }
 private void updatefooterheight (float delta) {
  setfooterviewheight ((int) (getfootheight () + delta));
 }
}
ios
  • Previous SSL certificate configuration for Nginx server and reverse proxy configuration for SSL
  • Next Mouse over the jQuery pop-up to enlarge the picture special effects