当前位置: 移动技术网 > IT编程>移动开发>Android > AndroidUI组件SlidingTabLayout实现ViewPager页滑动效果

AndroidUI组件SlidingTabLayout实现ViewPager页滑动效果

2019年07月24日  | 移动技术网IT编程  | 我要评论

地骨皮的作用与功效,唯爱极品萌公主,新乡市孟钢

使用slidingtablayout需要准备2个类,分别是 slidingtablayout,与slidingtabstrip,,放进项目中时只用修改下包名即可。

效果制作的不是很好。
这篇文章,也是在网上搜了很多资源参考,对 slidingtablayout.java和slidingtabstrip.java进行了修改。大家可以更改他的格式字体大小、选中状态,分割线调整等等。先上传这两个文件,改动支出都做了注释。
slidingtablayout.java

/*
 * copyright (c) 2013 the android open source project
 *
 * licensed under the apache license, version 2.0 (the "license");
 * you may not use this file except in compliance with the license.
 * you may obtain a copy of the license at
 *
 *  http://www.apache.org/licenses/license-2.0
 *
 * unless required by applicable law or agreed to in writing, software
 * distributed under the license is distributed on an "as is" basis,
 * without warranties or conditions of any kind, either express or implied.
 * see the license for the specific language governing permissions and
 * limitations under the license.
 */

package com.example.my.slidingtablayout;

import android.content.context;
import android.content.res.typedarray;
import android.graphics.color;
import android.graphics.typeface;
import android.os.build;
import android.support.v4.view.pageradapter;
import android.support.v4.view.viewpager;
import android.util.attributeset;
import android.util.typedvalue;
import android.view.gravity;
import android.view.layoutinflater;
import android.view.view;
import android.widget.horizontalscrollview;
import android.widget.linearlayout;
import android.widget.textview;

/**
 * to be used with viewpager to provide a tab indicator component which give constant feedback as to
 * the user's scroll progress.
 * <p>
 * to use the component, simply add it to your view hierarchy. then in your
 * {@link android.app.activity} or {@link android.support.v4.app.fragment} call
 * {@link #setviewpager(viewpager)} providing it the viewpager this layout is being used for.
 * <p>
 * the colors can be customized in two ways. the first and simplest is to provide an array of colors
 * via {@link #setselectedindicatorcolors(int...)} and {@link #setdividercolors(int...)}. the
 * alternative is via the {@link tabcolorizer} interface which provides you complete control over
 * which color is used for any individual position.
 * <p>
 * the views used as tabs can be customized by calling {@link #setcustomtabview(int, int)},
 * providing the layout id of your custom layout.
 */
public class slidingtablayout extends horizontalscrollview {

 /**
  * allows complete control over the colors drawn in the tab layout. set with
  * {@link #setcustomtabcolorizer(tabcolorizer)}.
  */
 public interface tabcolorizer {

  /**
   * @return return the color of the indicator used when {@code position} is selected.
   */
  int getindicatorcolor(int position);

  /**
   * @return return the color of the divider drawn to the right of {@code position}.
   */
  int getdividercolor(int position);

 }

 private static final int title_offset_dips = 24;
 private static final int tab_view_padding_dips = 16; //内边距
 private static int tab_view_text_size_sp = 16; //字体大小

 private int mtitleoffset;

 private int mtabviewlayoutid;
 private int mtabviewtextviewid;

 // 定义两种需要添加的选项卡颜色
 private int mdefaulttextcolor;
 private int mselectedtextcolor;

 private viewpager mviewpager;
 private viewpager.onpagechangelistener mviewpagerpagechangelistener;

 private final slidingtabstrip mtabstrip;

 public slidingtablayout(context context) {
  this(context, null);
 }

 public slidingtablayout(context context, attributeset attrs) {
  this(context, attrs, 0);
 }

 public slidingtablayout(context context, attributeset attrs, int defstyle) {
  super(context, attrs, defstyle);

  // 获取选项卡颜色,如果未定义的话,则使用主题默认的颜色
  typedarray a = context.obtainstyledattributes(attrs,
    r.styleable.slidingtablayout);
  int defaulttextcolor = a.getcolor(
    r.styleable.slidingtablayout_android_textcolorprimary, 0);
  mdefaulttextcolor = a.getcolor(
    r.styleable.slidingtablayout_textcolortabdefault, defaulttextcolor);
  mselectedtextcolor = a.getcolor(
    r.styleable.slidingtablayout_textcolortabselected ,defaulttextcolor);
  a.recycle();


  // disable the scroll bar
  sethorizontalscrollbarenabled(false);
  // make sure that the tab strips fills this view
  setfillviewport(true);

  mtitleoffset = (int) (title_offset_dips * getresources().getdisplaymetrics().density);

  mtabstrip = new slidingtabstrip(context);
  addview(mtabstrip, layoutparams.match_parent, layoutparams.wrap_content);
 }

 // 在每次选项改变时更新选项卡文本颜色的新方法
 private void updateselectedtitle(int position) {
  final pageradapter adapter = mviewpager.getadapter();
  for (int i = 0; i < adapter.getcount(); i++) {
   final view tabview = mtabstrip.getchildat(i);
   if (textview.class.isinstance(tabview)) {
    textview titleview = (textview)tabview;
    boolean isselected = i == position;
    titleview.settextcolor(isselected ? mselectedtextcolor : mdefaulttextcolor);
   }
  }
 }
 /**
  * set the custom {@link tabcolorizer} to be used.
  * <p>
  * if you only require simple custmisation then you can use
  * {@link #setselectedindicatorcolors(int...)} and {@link #setdividercolors(int...)} to achieve
  * similar effects.
  */
 public void setcustomtabcolorizer(tabcolorizer tabcolorizer) {
  mtabstrip.setcustomtabcolorizer(tabcolorizer);
 }


 /**
  * sets the colors to be used for indicating the selected tab. these colors are treated as a
  * circular array. providing one color will mean that all tabs are indicated with the same color.
  */
 public void setselectedindicatorcolors(int... colors) {
  mtabstrip.setselectedindicatorcolors(colors);
 }

 /**
  * sets the colors to be used for tab dividers. these colors are treated as a circular array.
  * providing one color will mean that all tabs are indicated with the same color.
  */
 public void setdividercolors(int... colors) {
  mtabstrip.setdividercolors(colors);
 }

 //...设置字体大小
 public void settitlesize(int size) {
  this.tab_view_text_size_sp = size;
 }

 /**
  * set the {@link viewpager.onpagechangelistener}. when using {@link slidingtablayout} you are
  * required to set any {@link viewpager.onpagechangelistener} through this method. this is so
  * that the layout can update it's scroll position correctly.
  *
  * @see viewpager#setonpagechangelistener(viewpager.onpagechangelistener)
  */
 public void setonpagechangelistener(viewpager.onpagechangelistener listener) {
  mviewpagerpagechangelistener = listener;
 }

 /**
  * set the custom layout to be inflated for the tab views.
  *
  * @param layoutresid layout id to be inflated
  * @param textviewid id of the {@link textview} in the inflated view
  */
 public void setcustomtabview(int layoutresid, int textviewid) {
  mtabviewlayoutid = layoutresid;
  mtabviewtextviewid = textviewid;
 }

 /**
  * sets the associated view pager. note that the assumption here is that the pager content
  * (number of tabs and tab titles) does not change after this call has been made.
  */
 public void setviewpager(viewpager viewpager) {
  mtabstrip.removeallviews();

  mviewpager = viewpager;
  if (viewpager != null) {
   viewpager.setonpagechangelistener(new internalviewpagerlistener());
   populatetabstrip();
  }
 }

 /**
  * create a default view to be used for tabs. this is called if a custom tab view is not set via
  * {@link #setcustomtabview(int, int)}.
  */
 protected textview createdefaulttabview(context context) {
  textview textview = new textview(context);
  textview.setgravity(gravity.center);
  textview.settextsize(typedvalue.complex_unit_sp, tab_view_text_size_sp);
  textview.settypeface(typeface.default_bold);

  //...这会移除 holo 的默认背景强调以及选项卡的粗体文本
  if (build.version.sdk_int >= build.version_codes.honeycomb) {
   // if we're running on honeycomb or newer, then we can use the theme's
   // selectableitembackground to ensure that the view has a pressed state
   typedvalue outvalue = new typedvalue();
   getcontext().gettheme().resolveattribute(android.r.attr.selectableitembackground,
     outvalue, true);
   textview.setbackgroundresource(outvalue.resourceid);
  }

  if (build.version.sdk_int >= build.version_codes.ice_cream_sandwich) {
   // if we're running on ics or newer, enable all-caps to match the action bar tab style
   textview.setallcaps(true);
  }

  int padding = (int) (tab_view_padding_dips * getresources().getdisplaymetrics().density);
  textview.setpadding(padding, padding, padding, padding);

  return textview;
 }

 private void populatetabstrip() {
  final pageradapter adapter = mviewpager.getadapter();
  final onclicklistener tabclicklistener = new tabclicklistener();

  for (int i = 0; i < adapter.getcount(); i++) {
   view tabview = null;
   textview tabtitleview = null;

   if (mtabviewlayoutid != 0) {
    // if there is a custom tab view layout id set, try and inflate it
    tabview = layoutinflater.from(getcontext()).inflate(mtabviewlayoutid, mtabstrip,
      false);
    tabtitleview = (textview) tabview.findviewbyid(mtabviewtextviewid);
   }

   if (tabview == null) {
    tabview = createdefaulttabview(getcontext());
   }

   if (tabtitleview == null && textview.class.isinstance(tabview)) {
    tabtitleview = (textview) tabview;
   }

   tabtitleview.settext(adapter.getpagetitle(i));
   //... 设置头部均分
   linearlayout.layoutparams layoutparams = new linearlayout.layoutparams(0, layoutparams.wrap_content, 1.0f);
   tabview.setlayoutparams(layoutparams);
   tabview.setonclicklistener(tabclicklistener);

   mtabstrip.addview(tabview);
  }
 }

 @override
 protected void onattachedtowindow() {
  super.onattachedtowindow();

  if (mviewpager != null) {
   scrolltotab(mviewpager.getcurrentitem(), 0);
  }
 }

 private void scrolltotab(int tabindex, int positionoffset) {
  final int tabstripchildcount = mtabstrip.getchildcount();
  if (tabstripchildcount == 0 || tabindex < 0 || tabindex >= tabstripchildcount) {
   return;
  }

  view selectedchild = mtabstrip.getchildat(tabindex);
  if (selectedchild != null) {

   // 调用在每次选项改变时更新文本颜色的新方案
   updateselectedtitle(tabindex);

   int targetscrollx = selectedchild.getleft() + positionoffset;

   if (tabindex > 0 || positionoffset > 0) {
    // if we're not at the first child and are mid-scroll, make sure we obey the offset
    targetscrollx -= mtitleoffset;
   }

   scrollto(targetscrollx, 0);
  }
 }

 private class internalviewpagerlistener implements viewpager.onpagechangelistener {
  private int mscrollstate;

  @override
  public void onpagescrolled(int position, float positionoffset, int positionoffsetpixels) {
   int tabstripchildcount = mtabstrip.getchildcount();
   if ((tabstripchildcount == 0) || (position < 0) || (position >= tabstripchildcount)) {
    return;
   }

   mtabstrip.onviewpagerpagechanged(position, positionoffset);

   view selectedtitle = mtabstrip.getchildat(position);
   int extraoffset = (selectedtitle != null)
     ? (int) (positionoffset * selectedtitle.getwidth())
     : 0;
   scrolltotab(position, extraoffset);

   if (mviewpagerpagechangelistener != null) {
    mviewpagerpagechangelistener.onpagescrolled(position, positionoffset,
      positionoffsetpixels);
   }
  }

  @override
  public void onpagescrollstatechanged(int state) {
   mscrollstate = state;

   if (mviewpagerpagechangelistener != null) {
    mviewpagerpagechangelistener.onpagescrollstatechanged(state);
   }
  }

  @override
  public void onpageselected(int position) {
   if (mscrollstate == viewpager.scroll_state_idle) {
    mtabstrip.onviewpagerpagechanged(position, 0f);
    scrolltotab(position, 0);
   }

   if (mviewpagerpagechangelistener != null) {
    mviewpagerpagechangelistener.onpageselected(position);
   }
  }

 }

 private class tabclicklistener implements onclicklistener {
  @override
  public void onclick(view v) {
   for (int i = 0; i < mtabstrip.getchildcount(); i++) {
    if (v == mtabstrip.getchildat(i)) {
     mviewpager.setcurrentitem(i);
     return;
    }
   }
  }
 }

}

slidingtabstrip.java

/*
 * copyright (c) 2013 the android open source project
 *
 * licensed under the apache license, version 2.0 (the "license");
 * you may not use this file except in compliance with the license.
 * you may obtain a copy of the license at
 *
 *  http://www.apache.org/licenses/license-2.0
 *
 * unless required by applicable law or agreed to in writing, software
 * distributed under the license is distributed on an "as is" basis,
 * without warranties or conditions of any kind, either express or implied.
 * see the license for the specific language governing permissions and
 * limitations under the license.
 */

package com.example.my.slidingtablayout;

import android.r;
import android.content.context;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.util.attributeset;
import android.util.typedvalue;
import android.view.view;
import android.widget.linearlayout;

class slidingtabstrip extends linearlayout {

 private static final int default_bottom_border_thickness_dips = 0; //去除阴影
 private static final byte default_bottom_border_color_alpha = 0x26;
 private static final int selected_indicator_thickness_dips = 4;  //设置滚动条的高度
 private static final int default_selected_indicator_color = 0xff33b5e5;


 private static final int default_divider_thickness_dips = 1;
 private static final byte default_divider_color_alpha = 0x20;
 private static final float default_divider_height = 0.5f;

 private final int mbottomborderthickness;
 private final paint mbottomborderpaint;

 private final int mselectedindicatorthickness;
 private final paint mselectedindicatorpaint;

 private final int mdefaultbottombordercolor;

 private final paint mdividerpaint;
 private final float mdividerheight;

 private int mselectedposition;
 private float mselectionoffset;

 private slidingtablayout.tabcolorizer mcustomtabcolorizer;
 private final simpletabcolorizer mdefaulttabcolorizer;

 slidingtabstrip(context context) {
  this(context, null);
 }

 slidingtabstrip(context context, attributeset attrs) {
  super(context, attrs);
  setwillnotdraw(false);

  final float density = getresources().getdisplaymetrics().density;

  typedvalue outvalue = new typedvalue();
  context.gettheme().resolveattribute(r.attr.colorforeground, outvalue, true);
  final int themeforegroundcolor = outvalue.data;

  mdefaultbottombordercolor = setcoloralpha(themeforegroundcolor,
    default_bottom_border_color_alpha);

  mdefaulttabcolorizer = new simpletabcolorizer();
  mdefaulttabcolorizer.setindicatorcolors(default_selected_indicator_color);
  mdefaulttabcolorizer.setdividercolors(setcoloralpha(themeforegroundcolor,
    default_divider_color_alpha));

  mbottomborderthickness = (int) (default_bottom_border_thickness_dips * density);
  mbottomborderpaint = new paint();
  mbottomborderpaint.setcolor(mdefaultbottombordercolor);

  mselectedindicatorthickness = (int) (selected_indicator_thickness_dips * density);
  mselectedindicatorpaint = new paint();

  mdividerheight = default_divider_height;
  mdividerpaint = new paint();
  mdividerpaint.setstrokewidth((int) (default_divider_thickness_dips * density));
 }

 void setcustomtabcolorizer(slidingtablayout.tabcolorizer customtabcolorizer) {
  mcustomtabcolorizer = customtabcolorizer;
  invalidate();
 }

 void setselectedindicatorcolors(int... colors) {
  // make sure that the custom colorizer is removed
  mcustomtabcolorizer = null;
  mdefaulttabcolorizer.setindicatorcolors(colors);
  invalidate();
 }

 void setdividercolors(int... colors) {
  // make sure that the custom colorizer is removed
  mcustomtabcolorizer = null;
  mdefaulttabcolorizer.setdividercolors(colors);
  invalidate();
 }

 void onviewpagerpagechanged(int position, float positionoffset) {
  mselectedposition = position;
  mselectionoffset = positionoffset;
  invalidate();
 }

 @override
 protected void ondraw(canvas canvas) {
  final int height = getheight();
  final int childcount = getchildcount();
  final int dividerheightpx = (int) (math.min(math.max(0f, mdividerheight), 1f) * height);
  final slidingtablayout.tabcolorizer tabcolorizer = mcustomtabcolorizer != null
    ? mcustomtabcolorizer
    : mdefaulttabcolorizer;

  // thick colored underline below the current selection
  if (childcount > 0) {
   view selectedtitle = getchildat(mselectedposition);
   int left = selectedtitle.getleft();
   int right = selectedtitle.getright();
   int color = tabcolorizer.getindicatorcolor(mselectedposition);

   if (mselectionoffset > 0f && mselectedposition < (getchildcount() - 1)) {
    int nextcolor = tabcolorizer.getindicatorcolor(mselectedposition + 1);
    if (color != nextcolor) {
     color = blendcolors(nextcolor, color, mselectionoffset);
    }

    // draw the selection partway between the tabs
    view nexttitle = getchildat(mselectedposition + 1);
    left = (int) (mselectionoffset * nexttitle.getleft() +
      (1.0f - mselectionoffset) * left);
    right = (int) (mselectionoffset * nexttitle.getright() +
      (1.0f - mselectionoffset) * right);
   }

   mselectedindicatorpaint.setcolor(color);

   canvas.drawrect(left, height - mselectedindicatorthickness, right,
     height, mselectedindicatorpaint);
  }

  // thin underline along the entire bottom edge
  canvas.drawrect(0, height - mbottomborderthickness, getwidth(), height, mbottomborderpaint);

  // vertical separators between the titles
  int separatortop = (height - dividerheightpx) / 2;
  for (int i = 0; i < childcount - 1; i++) {
   view child = getchildat(i);
   mdividerpaint.setcolor(tabcolorizer.getdividercolor(i));
   canvas.drawline(child.getright(), separatortop, child.getright(),
     separatortop + dividerheightpx, mdividerpaint);
  }
 }

 /**
  * set the alpha value of the {@code color} to be the given {@code alpha} value.
  */
 private static int setcoloralpha(int color, byte alpha) {
  return color.argb(alpha, color.red(color), color.green(color), color.blue(color));
 }

 /**
  * blend {@code color1} and {@code color2} using the given ratio.
  *
  * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,
  *    0.0 will return {@code color2}.
  */
 private static int blendcolors(int color1, int color2, float ratio) {
  final float inverseration = 1f - ratio;
  float r = (color.red(color1) * ratio) + (color.red(color2) * inverseration);
  float g = (color.green(color1) * ratio) + (color.green(color2) * inverseration);
  float b = (color.blue(color1) * ratio) + (color.blue(color2) * inverseration);
  return color.rgb((int) r, (int) g, (int) b);
 }

 private static class simpletabcolorizer implements slidingtablayout.tabcolorizer {
  private int[] mindicatorcolors; //
  private int[] mdividercolors;  //


  @override
  public final int getindicatorcolor(int position) {
   return mindicatorcolors[position % mindicatorcolors.length];
  }

  @override
  public final int getdividercolor(int position) {
   return mdividercolors[position % mdividercolors.length];
  }

  void setindicatorcolors(int... colors) {
   mindicatorcolors = colors;
  }

  void setdividercolors(int... colors) {
   mdividercolors = colors;
  }
 }
}

上边因为使用了自定义的颜色,所以这里要在attrs.xml声明一下,不然找不到:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="slidingtablayout">
  <attr name="android:textcolorprimary" />
  <attr name="textcolortabdefault" format="color" />
  <attr name="textcolortabselected" format="color" />
 </declare-styleable>
</resources>

布局文件也要用到自定义:

<?xml version="1.0" encoding="utf-8"?>
<linearlayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 android:id="@+id/activity_main"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:context="com.example.my.slidingtablayout.mainactivity">
 <!-- 在上方就在上面,在下方就在下面(tab栏) -->
 <com.example.my.slidingtablayout.slidingtablayout
  android:id="@+id/sliding"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  app:textcolortabdefault="#000000"
  app:textcolortabselected="@color/coloraccent"
  />

 <android.support.v4.view.viewpager
  android:id="@+id/view_pager"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  />
</linearlayout>

最后一道就是在你的activity运用这种开源:可以调整之处也做了说明

package com.example.my.slidingtablayout;

import android.graphics.color;
import android.os.bundle;
import android.support.v4.view.pageradapter;
import android.support.v4.view.viewpager;
import android.support.v7.app.appcompatactivity;
import android.view.view;
import android.view.viewgroup;
import android.widget.linearlayout;

import java.util.arraylist;

public class mainactivity extends appcompatactivity {
 //创建 颜色数组 用来做viewpager的背景
 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_main);
  viewpager pager = (viewpager) findviewbyid(r.id.view_pager);
  slidingtablayout tab = (slidingtablayout) findviewbyid(r.id.sliding);
  tab.setdividercolors(color.transparent); //设置标题的分割线
  tab.setselectedindicatorcolors(color.rgb(51, 181, 229)); //设置滚动条的颜色
  tab.settitlesize(18); //...设置字体的颜色,默认16

  myadapte adapter = new myadapte();
  pager.setadapter(adapter);
  tab.setviewpager(pager);
 }

 int[] colors = {0xff123456, 0xff654321, 0xff336699};

 class myadapte extends pageradapter {
  //可以考虑把这个数组添加到集合里面
  string[] titles = {"aa", "bb", "cc"};


  arraylist<linearlayout> layouts = new arraylist<linearlayout>();

  myadapte() {

   for (int i = 0; i < 3; i++) {
    linearlayout l = new linearlayout(mainactivity.this);
    l.setbackgroundcolor(colors[i]);
    l.setlayoutparams(new viewgroup.layoutparams(viewgroup.layoutparams.match_parent, viewgroup.layoutparams.match_parent));
    layouts.add(l);
   }

  }

  @override
  public int getcount() {
   return layouts.size();
  }

  @override
  public boolean isviewfromobject(view view, object o) {
   return view == o;
  }

  @override
  public object instantiateitem(viewgroup container, int position) {
   linearlayout l = layouts.get(position);
   container.addview(l);
   return l;
  }

  @override
  public void destroyitem(viewgroup container, int position, object object) {
   container.removeview(layouts.get(position));
  }

  @override
  public charsequence getpagetitle(int position) {
   //...可以返回集合list.get(position);
   return titles[position];
  }
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网