Android multiple tab tab Toggle effect _android

Source: Internet
Author: User
Tags flush int size

In the previous issue, we did a two tab switch and a drop down refresh effect on the suspension head, later, the project requirements changed to three tab, at that time can be measured, if the change from the previous, it is not not, but to remember each other too much of the state, it is easy to make mistakes. decided to implement this effect again, to write a demo, this period project has been updated two version. Demo also wood has become an article.

The previous version uses a ListView that pulls down the refresh, then adds two headers to the ListView and uses an identical toggle tab on top of the layout, and if you haven't seen the previous version, look at the previous version, ListView Multiple tab on the sliding suspension.

Based on the above ideas we first look at the page layout: main_activity

<?xml version= "1.0" encoding= "Utf-8"?> <relativelayout xmlns:android= "http://schemas.android.com/apk/res/" Android "Android:layout_width=" Match_parent "android:layout_height=" match_parent "android:background=" @color Color_gray_eaeaea "> <android.support.v4.view.viewpager android:id=" @+id/pager "Android:layout_width=" mat Ch_parent "android:layout_height=" match_parent "/> <linearlayout android:id=" @+id/header "Android:lay Out_width= "Match_parent" android:layout_height= "wrap_content" android:background= "@color/white" android:orient ation= "vertical" > <imageview android:id= "@+id/show_event_detail_bg" android:layout_width= "Fill_par" 
      Ent "android:layout_height=" 135dip "android:contentdescription=" "@string/empty" android:scaletype= "Fitxy"
      android:src= "@drawable/header_default_bk"/> <textview android:id= "@+id/show_event_detail_desc" Android:layout_width= "Wrap_content"Android:layout_height=" 104dip "android:paddingbottom=" 24dip "android:layout_marginleft=" 15dip "a ndroid:layout_marginright= "15dip" android:paddingtop= "25dip" android:text= "@string/head_title_desc" Andr Oid:textcolor= "@color/color_black_333333" android:textsize= "14sp"/> <view style= "@style/horizontal_gray_ Divider "/> <view style=" @style/horizontal_gray_divider "/> <com.example.refreashtabview.sliding.pag Erslidingtabstrip android:id= "@+id/show_tabs" android:layout_width= "Match_parent" android:layout_height=

 "44dip" android:background= "@color/white"/> </LinearLayout> </RelativeLayout>

The page uses a two layer, the back layer for the Viewpager, the front for the suspension Head and tab switch, in this we should all think how to achieve, Viewpager added already fragment, each fragment inside add a can pull down to refresh the ListView, Controls the position of the previous Frame page according to the ListView slide.

Let's take a look at the page code, Mainacitivity.java.

public class Mainactivity extends Actionbaractivity implements Onpagechangelistener, Scrolltabholder {private PAGERSL

  Idingtabstrip tabs;

  Private Viewpager Viewpager;

  Private Slidingpageradapter adapter;

  Private LinearLayout header;
  private int headerheight;

  private int Headertranslationdis;
    @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
    Setcontentview (r.layout.main_activity);
    Getheaderheight ();
    Findviews ();
    Setuppager ();
  Setuptabs ();
    private void Findviews () {tabs = (Pagerslidingtabstrip) Findviewbyid (r.id.show_tabs);
    Viewpager = (Viewpager) Findviewbyid (R.id.pager);
  Header = (linearlayout) Findviewbyid (R.id.header);
    private void Getheaderheight () {headerheight = Getresources (). Getdimensionpixelsize (R.dimen.max_header_height);
  Headertranslationdis =-getresources (). Getdimensionpixelsize (R.dimen.header_offset_dis);
   private void Setuppager () { adapter = new Slidingpageradapter (Getsupportfragmentmanager (), this, Viewpager);
    Adapter.settabholderscrollinglistener (this);//Control page Slide Viewpager.setoffscreenpagelimit (Adapter.getcachecount ());
    Viewpager.setadapter (adapter);
  Viewpager.setonpagechangelistener (this);
    private void Setuptabs () {Tabs.setshouldexpand (true);
    Tabs.setindicatorcolorresource (R.color.color_purple_bd6aff);
    Tabs.setunderlinecolorresource (R.color.color_purple_bd6aff);
    Tabs.setcheckedtextcolorresource (R.color.color_purple_bd6aff);
  Tabs.setviewpager (Viewpager); @Override public void onpagescrolled (int position, float positionoffset, int positionoffsetpixels) {Tabs.onpag
  escrolled (position, Positionoffset, positionoffsetpixels);
    @Override public void onpageselected (int position) {tabs.onpageselected (position);
    Relocation = true;
    sparsearraycompat<scrolltabholder> scrolltabholders = Adapter.getscrolltabholders (); Scrolltabholder CurrEntholder = scrolltabholders.valueat (position);
      if (need_relayout) {currentholder.adjustscroll (int) (Header.getheight () + headertop))//fix the offset to roll out} else {

  Currentholder.adjustscroll ((int) (Header.getheight () + viewhelper.gettranslationy (header));//fix the offset to roll out}}
  @Override public void onpagescrollstatechanged (int state) {tabs.onpagescrollstatechanged);

  @Override public void Adjustscroll (int scrollheight) {} private Boolean relocation = false;

  private int headerscrollsize = 0; public static Final Boolean need_relayout = Integer.valueof (Build.VERSION.SDK). Intvalue () < Build.version_codes.

  Honeycomb;

  private int headertop = 0; When refreshing the head display, there is no onscroll callback, only @Override public void onscroll (Abslistview view, int firstvisibleitem, int visibleite
    Mcount, int totalitemcount, int pageposition) {if (Viewpager.getcurrentitem ()!= pageposition) {return; } if (headerscrollsize = 0 && ReLocation) {relocation = false;
    Return
    } relocation = false;
    int scrolly = Math.max (-getscrolly (view), Headertranslationdis);
      if (need_relayout) {headertop = scrolly; Header.post (New Runnable () {@Override public void run () {LOG.E ("Main", "scorry1=" + headertop)
          ;
        Header.layout (0, Headertop, Header.getwidth (), Headertop + header.getheight ());
    }
      });
    else {viewhelper.settranslationy (header, scrolly); }/** * Mainly counts this thing, Pulltorefreshlistview inserts a flush head, therefore calculates the current offset according to the different situation </br> * * When refreshing: Refresh the head display, so the offset should be added to the flush header.
   When the value is not refreshed: The offset does not calculate the head. 
   * * When Firstvisibleposition >1, the items in ListView begin to show, so it's important to calculate the offset (in fact, as long as an item is displayed, the upward offset is already greater than the head's maximum offset, so inaccurate and not related) *
    * @param view * @return/public int getscrolly (Abslistview view) {View c = view.getchildat (0);
    if (c = = null) {return 0;
    int top = C.gettop (); int firstvisibleposition = View.getfirsTvisibleposition ();
    if (firstvisibleposition = = 0) {return-top + headerscrollsize;
    else if (firstvisibleposition = 1) {return-top;
    else {return-top + (firstVisiblePosition-2) * C.getheight () + headerheight; The Onheadscroll is mutually exclusive and cannot be executed concurrently @Override public void Onheaderscroll (boolean isrefreashing, int value, int pageposi
    tion) {if (Viewpager.getcurrentitem ()!= pageposition) {return;
    } headerscrollsize = value; if (need_relayout) {header.post (new Runnable () {@Override public void run () {LOG.E ("Ma
          In "," scorry= "+ (-headerscrollsize));
        Header.layout (0,-headerscrollsize, Header.getwidth (),-headerscrollsize + header.getheight ());
    }
      });
    }else{Viewhelper.settranslationy (header,-value);
 }
  }

}


Explain the above code, the interface of the next layer for Viewpager, which added a number of fragment, each fragment inside a listivew,listview to occupy a height of the same as the suspension header, This can display areas for the visible area, and then monitor the ListView Onscorll, according to the current display of the ListView of the item height to control the previous layer of the suspension position, this place to pay attention to, each time you switch tab, To notify the current offset to the current switch tab, such as TAB1, slide up, shadow hidden floating head, when switching from Tab1 to TAB2, this is the tab2 position to revise upward, the correction distance for the suspension head slide out of the distance. The other part of the code page is relatively simple, look at it, second, open source control Pulltorefreshlistview I modified the offset when the refresh, when the distance notification to the interface, so in the Drop-down refresh, the entire head downward offset,

PS: As you can see in the above code, we use different animations for different versions, This is because before 3.0, the displacement animation appears to move the position, but in fact the control is still in the original position, for this purpose to deal with different versions of the animation, otherwise the tab click event on the 2.X version or in the original position. The above animation uses the Nineold control, also may write itself, this part of the animation is relatively simple.

Fragment is added to the viewpager above, let's take a look at Tab1listfragment.java

public class Tab1listfragment extends Scrolltabholderfragment {private Pulltorefreshlistview listView;

  Private View Placeholderview;

  Private arrayadapter<string> adapter;

  Private arraylist<string> ListItems;

  Private Handler Handler;
  Public tab1listfragment () {This.setfragmentid (PageAdapterTab.PAGE_TAB1.fragmentId);
  @Override public void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); @Override public View Oncreateview (layoutinflater inflater, ViewGroup container, Bundle savedinstancestate) {R
  Eturn inflater.inflate (R.layout.page_tab_fragment_layout, container, false); @Override public void onactivitycreated (Bundle savedinstancestate) {super.onactivitycreated (savedinstancestate
    );
    Findviews ();
  Initlistview ();
    @SuppressLint ("Inflateparams") private void Findviews () {handler = new handler (Looper.getmainlooper ()); ListView = (Pulltorefreshlistview) GetView (). FINDVIewbyid (R.id.page_tab_listview);
    private void Initlistview () {Setlistviewlistener ();
    Listviewaddheader ();
  Listviewloaddata ();

      private void Setlistviewlistener () {Listview.setonrefreshlistener () {new onrefreshlistener2<listview> () {
      @Override public void Onpulldowntorefresh (pulltorefreshbase<listview> refreshview) {loadnews (); @Override public void Onpulluptorefresh (pulltorefreshbase<listview> refreshview) {Loado
      LDS ();

    }

    }); Listview.setonscrolllistener (New Onscrolllistener () {@Override public void onscrollstatechanged (Abslistview view, int scrollstate) {} @Override public void onscroll (Abslistview view, int firstvisibleitem, int v Isibleitemcount, int totalitemcount) {if (Scrolltabholder!= null) {Scrolltabholder.onscroll (view, Fir
        Stvisibleitem, VisibleItemCount, Totalitemcount, Getfragmentid ()); }
      }
    }); Listview.setonheaderscrolllistener (New Onheaderscrolllistener () {@Override public void Onheaderscroll (Boolea N Isrefreashing, Boolean istop, int value) {if (Scrolltabholder!= null && istop) {scrolltabho
        Lder.onheaderscroll (isrefreashing, Value, Getfragmentid ());
  }
      }
    });
    private void Listviewaddheader () {Placeholderview = new LinearLayout (getactivity ()); Abslistview.layoutparams params = new Layoutparams (AbsListView.LayoutParams.MATCH_PARENT, Getresources (). getdimen
    Sionpixelsize (r.dimen.max_header_height));
    Placeholderview.setlayoutparams (params);
  Listview.getrefreshableview (). Addheaderview (Placeholderview);
    } protected void Listviewloaddata () {ListItems = new arraylist<string> ();
    for (int i = 1; I <= i++) {listitems.add ("Currnet page:" + (Getfragmentid () + 1) + "Item--" + i); } adapter = new arrayadapter<string> (getactivity (), R.layout.lisT_item, Android.
    R.id.text1, ListItems);
    Listview.setadapter (adapter);
  Loadnews (); /** * Pull out the old data/private void Loadnews () {handler.postdelayed (new Runnable () {//Simulate remote fetch data @O
            Verride public void Run () {Stoprefresh ();
            Listitems.clear ();  for (int i = 1; I <= i++) {//Listitems.add ("Currnet page:" + (Getfragmentid () +//1)
            + "Item--" + i);
          }//Notifyadpterdatachanged ();
  }, 300);
    private void notifyadpterdatachanged () {if (adapter!= null) {adapter.notifydatasetchanged (); } protected void Loadolds () {handler.postdelayed (new Runnable () {//Simulate remote fetch data @Override PU
            Blic void Run () {Stoprefresh ();
            int size = Listitems.size () + 1; for (int i = size; I < size + ++i) {listitems.add ("Currnet page:" + GetfragmentiD () + 1) + "Item--" + i);
          } notifyadpterdatachanged ();
  }, 300);  }//Pulltorefreshlistview automatically adds a header @Override public void adjustscroll (int scrollheight) {if (scrollheight = =
    0 && Listview.getrefreshableview (). Getfirstvisibleposition () >= 2) {return;
    }//log.d (Gettag (), "scrollheight:" + scrollheight);
Listview.getrefreshableview (). Setselectionfromtop (2, scrollheight);
LOG.D (Gettag (), "getscrolly:" + getscrolly (Listview.getrefreshableview ()); Handler.postdelayed (New Runnable () {////@Override//public void Run () {//LOG.D (Gettag (), "GE       
Tscrolly: "+ getscrolly (Listview.getrefreshableview ()));
  }//}, 5000);
    public int getscrolly (Abslistview view) {View c = view.getchildat (0);
    if (c = = null) {return 0;
    int top = C.gettop ();
    int firstvisibleposition = View.getfirstvisibleposition (); if (firstvisibleposition = 0) {return-top;
    else if (firstvisibleposition = = 1) {return top;
    else {return-top + (firstVisiblePosition-2) * C.getheight () + 683;
    } protected void Updatelistview () {if (adapter!= null) {adapter.notifydatasetchanged ();
  } protected void Stoprefresh () {listview.onrefreshcomplete ();
 }

}


The interface in the code above is that XML contains a pulltorefreshlistview, simpler this place is not posted, we see in Listviewaddheader, this place adds a head with a suspended top, This can be presented to the content area, will not be suspended head occlusion, followed by the list in the listener we will onscorll to the main interface, so ListView scrolling, you can calculate the current rolling distance, fixed the distance of the suspension head.

We'll post the rest of the code Scrolltabholderfragment.java and Scrolltabholder.java.

 public abstract class Scrolltabholderfragment extends Fragment implements Scrolltabholder {p

  rivate int Fragmentid;

  protected Scrolltabholder Scrolltabholder;
  public void Setscrolltabholder (Scrolltabholder scrolltabholder) {this.scrolltabholder = Scrolltabholder;
      @Override public void Onscroll (Abslistview view, int firstvisibleitem, int visibleitemcount, int totalitemcount,  int pageposition) {//nothing} @Override public void Onheaderscroll (boolean isrefreashing, int value, int
  pageposition) {} public int Getfragmentid () {return fragmentid;
  The public void Setfragmentid (int fragmentid) {this.fragmentid = Fragmentid;

  } public interface Scrolltabholder {void adjustscroll (int scrollheight);

  void Onscroll (Abslistview view, int firstvisibleitem, int visibleitemcount, int totalitemcount, int pageposition);
void Onheaderscroll (Boolean isrefreashing, int value, int pageposition); }


Finally, let's look at Adaper

public class Slidingpageradapter extends Fragmentpageradapter {protected final scrolltabholderfragment[] fragments;

  Protected final context;
  Private sparsearraycompat<scrolltabholder> mscrolltabholders;

  Private Scrolltabholder Mlistener;
  public int Getcachecount () {return pageadaptertab.values (). length;
    Slidingpageradapter (fragmentmanager FM, context, Viewpager Pager) {super (FM);
    Fragments = new Scrolltabholderfragment[pageadaptertab.values (). length];
    This.context = context;
    Mscrolltabholders = new sparsearraycompat<scrolltabholder> ();
  INIT (FM);
        } private void Init (Fragmentmanager FM) {for (Pageadaptertab tab:PageAdapterTab.values ()) {try {

        Scrolltabholderfragment fragment = null;
        List<fragment> fs = Fm.getfragments (); if (fs!= null) {for (Fragment f:fs) {if (f.getclass () = = Tab.clazz) {Fragment = (ScrolltabholdeRfragment) F;
            Break }} if (fragment = null) {fragment = (scrolltabholderfragment) tab.clazz.newInsta
        NCE ();
      } Fragments[tab.tabindex] = fragment;
      catch (Instantiationexception e) {e.printstacktrace ();
      catch (Illegalaccessexception e) {e.printstacktrace ();
  }} public void Settabholderscrollinglistener (Scrolltabholder listener) {Mlistener = listener;
    @Override public scrolltabholderfragment getitem (int pos) {scrolltabholderfragment fragment = Fragments[pos];
    Mscrolltabholders.put (POS, fragment);
    if (Mlistener!= null) {Fragment.setscrolltabholder (Mlistener);
  return fragment;
  Public sparsearraycompat<scrolltabholder> Getscrolltabholders () {return mscrolltabholders;
  @Override public int GetCount () {return pageadaptertab.values (). length; } @Override Public Charsequence GetpagEtitle (int position) {pageadaptertab tab = pageadaptertab.fromtabindex (position); int resid = tab!= null?
    tab.resid:0; Return resid!= 0?
  Context.gettext (RESID): "";
 }

}

The


Slidingpageradapter inherits from the Fragmentpageradapter, passing a callback from the main interface, which is passed to each fragment in callback, This links the fragment with the activity. In fact, there are many ways to get a callback in an activity, such as in a fragment attach. There's another pageadaptertab in the code, what's it doing? Take a look at the code

public enum Pageadaptertab {
  page_tab1 (0, Tab1listfragment.class, r.string.page_tab1),

  page_tab2 (1, Tab2listfragment.class, R.STRING.PAGE_TAB2),

  page_tab3 (2, Tab3listfragment.class, r.string.page_tab3),
  ;

  public final int tabIndex;

  Public final class<? Extends fragment> clazz;

  public final int resid;

  public final int fragmentid;

  Private Pageadaptertab (int index, CLASS<? extends fragment> clazz, int resid) {
    this.tabindex = index;
    This.clazz = Clazz;
    This.resid = Resid;
    This.fragmentid = index;
  }

  public static final Pageadaptertab fromtabindex (int tabIndex) {for
    (Pageadaptertab value:PageAdapterTab.values () {
      if (Value.tabindex = = TabIndex) {return
        value;
      }
    }

    return null;
  }
}

is an enumeration class that configures the current fragment to be displayed, so that you can only modify the enumeration if you want to add it later.

By the end of the whole project, we cut a few pictures to see the effect:

Finally, in retrospect, the layout of the two-layer, thick layer for a viewpager, which contains a number of fragment, the previous layer for a floating head and tab, when sliding ListView will be the current display position to the main interface, while changing the location of the main interface.

The code address is as follows: Https://github.com/FreeSunny/RefreashTabView

The above is the entire content of this article, I hope to help you learn.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.