欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android自定义TabLayout效果

程序员文章站 2023-12-09 18:05:27
周末就要到了,今天项目中遇到这样一个tab,选中tab的背景是个圆角矩形,方向指向器没有了,这样普通的tablayout不能满足我的要求,可能会想到动态的去设置选中tab的...

周末就要到了,今天项目中遇到这样一个tab,选中tab的背景是个圆角矩形,方向指向器没有了,这样普通的tablayout不能满足我的要求,可能会想到动态的去设置选中tab的背景不就可以了,但是那样的话太生硬了,没有动画效果,其实想想也还比较简单,今天就简单的说一说这个yzztab。效果如下图:

Android自定义TabLayout效果

这里是四个tab,一版只显示3个,这里假设有num个tab,当滑动到第3个时,这里就需要考虑如何让tablayout和指示器一起移动呢?

@override
public void onpagescrolled(int position, float positionoffset, int positionoffsetpixels) {
 if (positionoffset>1){
  return;
 }
 int leftcop = (int) (positionoffset*(getmeasuredwidth()/mmaxlinenum)+position*getmeasuredwidth()/mmaxlinenum);
 if (leftcop!=leftfortablayout){
  //这里要做判断是否滑动,当选择的位置大于tablayout中显示的最大数-1时,会向左右滑动,指示器也会
  //跟这滑动,相对静止,否则指示器滑动,tab布局不移动
  if (position>=mmaxlinenum-1) {
   scrollcontent += leftcop - leftfortablayout;
   scrollto(scrollcontent, 0);
   //这里要重新layout
   update();
  }
  leftfortablayout = leftcop;
  invalidate();
 }
}

首先,在viewpage的监听中,positionoffset有时候可能大于1,这点需要注意的,当两次left的坐标相等 时,我们就不进行绘制了,接下来就是
如何确定left的值了,对于这点我也想了很久,最后终于得出结论:

int leftcop = (int) (positionoffset*(getmeasuredwidth()/mmaxlinenum)+position*getmeasuredwidth()/mmaxlinenum);

因为当positionoffset的值在向右滑动80%左右的时候getcurrentitem()的值会发生变化,这点可以试验一下,所以getcurrentitem()方法不能用了,只能用参数position.layout滑动的实际代码注释很详细了,我就不再阐述了,可以试试。在布局滑动了以后,必须要layout,不然view的属性不会变,点击没法应,但是也可以不更新,动态的告诉用户点击的真是tab,这样也可以。

 private void update() {
 for (int i = 0; i <mchildcount ; i++) {
  view v = getchildat(i);
  v.setleft(v.getleft()+scrollcontent);
 }
 //必须调用,不然不会重新layout
 requestlayout();
}

接下来就是绘制了,viewgroup是默认不调用ondraw(canvas canvas)方法的,原因很简单,viewgroup是个容器,主要作用是起承载作用,绘画就交给子view了,但是还是有办法让其调用该方法的,如下:

 setwillnotdraw(false);

这就告诉该容器,需要绘制;

接下来就是绘制指向器和选中背景了,一个圆角矩形和一条线,比较简单,我就不再详细说明了。

@override
protected void ondraw(canvas canvas) {
 //left = getmeasuredwidth() / mchildcount * mselectposition;
 super.ondraw(canvas);
 mpaint.setcolor(color.green);
 int top = getmeasuredheight() / 4;
 int right = leftfortablayout + getmeasuredwidth() / mmaxlinenum;
 int bottom = getmeasuredheight() - getmeasuredheight() / 4;
 rectf rectf = new rectf(leftfortablayout, top, right, bottom);
 mpaint.setantialias(true);
 mpaint.setstyle(paint.style.fill);
 canvas.drawroundrect(rectf, 10, 10, mpaint);
 mpaint.setcolor(color.red);
 mpaint.setstrokewidth(5);
 canvas.drawline(leftfortablayout,getmeasuredheight()-5,right,getmeasuredheight()-5,mpaint);

}

接下来介绍建与viewpager建立关联的方法

 /**
 * 于viewpager建立联系,这里必须先要给viewpager设置adapter
 *
 * @param viewpager
 */
public void setupwithviewpager(viewpager viewpager) {
 mviewpager = viewpager;
 mchildcount = viewpager.getadapter().getcount();
 mselectposition = viewpager.getcurrentitem();
 viewpager.setonpagechangelistener(this);
}

初始化的方法

/**
 * 为tab添加view
 */
private void init() {
 setwillnotdraw(false);
 mpaint = new paint();
 for (int i = 0; i < mchildcount; i++) {
  final textview tv = new textview(getcontext());
  int w = getmeasuredwidth()/mmaxlinenum;
  linearlayout.layoutparams lp = new layoutparams(w, viewgroup.layoutparams.match_parent);
  tv.settext("tab" + i);
  tv.setgravity(gravity.center);
  tv.setlayoutparams(lp);
  final int finali = i;
  tv.setonclicklistener(new onclicklistener() {
   @override
   public void onclick(view v) {
    if (montabselecterlistener != null){
     montabselecterlistener.selecter(finali,tv);
    }
   }
  });
  addview(tv);
 }
}

这里只是很简单的加了几个textview进去,也可以弄个方法,通过用户动态添加自己想要的view,都可以实现的。至于监听的话就很简单了.上面已经写到了。

yzztab的代码

package a6he.android.yzz.com.mytablayout;
import android.content.context;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.graphics.rect;
import android.graphics.rectf;
import android.support.v4.view.viewpager;
import android.util.attributeset;
import android.util.log;
import android.view.gravity;
import android.view.view;
import android.view.viewgroup;
import android.widget.linearlayout;
import android.widget.switch;
import android.widget.textview;

/**
 * created by yzz on 2017/2/24 0024.
 * <p/>
 * 实现背景随着viewpager的滑动跟着移动
 */
public class yzztab extends linearlayout implements viewpager.onpagechangelistener {

private viewpager mviewpager;
private paint mpaint;
//tab的数量
private int mchildcount;
//tab选中的位置
private int mselectposition;
//绘制指向器的左顶点
private int leftfortablayout = 0;
private int leftforinvidator = 0;
private int mmaxlinenum = 3;
private int scrollcontent = 0;
private ontabselecterlistener montabselecterlistener;

public yzztab(context context) {
 super(context);
}

public yzztab(context context, attributeset attrs) {
 super(context, attrs);
}

public yzztab(context context, attributeset attrs, int defstyleattr) {
 super(context, attrs, defstyleattr);
}

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

}

@override
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
 super.onmeasure(widthmeasurespec, heightmeasurespec);
 init();
}


/**
 * 于viewpager建立联系,这里必须先要给viewpager设置adapter
 *
 * @param viewpager
 */
public void setupwithviewpager(viewpager viewpager) {
 mviewpager = viewpager;
 mchildcount = viewpager.getadapter().getcount();
 mselectposition = viewpager.getcurrentitem();
 viewpager.setonpagechangelistener(this);

}

/**
 * 为tab添加view
 */
private void init() {
 setwillnotdraw(false);
 mpaint = new paint();
 for (int i = 0; i < mchildcount; i++) {
  final textview tv = new textview(getcontext());
  int w = getmeasuredwidth()/mmaxlinenum;
  linearlayout.layoutparams lp = new layoutparams(w, viewgroup.layoutparams.match_parent);
  tv.settext("tab" + i);
  tv.setgravity(gravity.center);
  tv.setlayoutparams(lp);
  final int finali = i;
  tv.setonclicklistener(new onclicklistener() {
   @override
   public void onclick(view v) {
    if (montabselecterlistener != null){
     montabselecterlistener.selecter(finali,tv);
    }
   }
  });
  addview(tv);
 }
}

@override
protected void ondraw(canvas canvas) {
 //left = getmeasuredwidth() / mchildcount * mselectposition;
 super.ondraw(canvas);
 mpaint.setcolor(color.green);
 int top = getmeasuredheight() / 4;
 int right = leftfortablayout + getmeasuredwidth() / mmaxlinenum;
 int bottom = getmeasuredheight() - getmeasuredheight() / 4;
 rectf rectf = new rectf(leftfortablayout, top, right, bottom);
 mpaint.setantialias(true);
 mpaint.setstyle(paint.style.fill);
 canvas.drawroundrect(rectf, 10, 10, mpaint);
 mpaint.setcolor(color.red);
 mpaint.setstrokewidth(5);
 canvas.drawline(leftfortablayout,getmeasuredheight()-5,right,getmeasuredheight()-5,mpaint);

}

@override
public void onpagescrolled(int position, float positionoffset, int positionoffsetpixels) {
 if (positionoffset>1){
  return;
 }
 int leftcop = (int) (positionoffset*(getmeasuredwidth()/mmaxlinenum)+position*getmeasuredwidth()/mmaxlinenum);
 if (leftcop!=leftfortablayout){
  //这里要做判断是否滑动,当选择的位置大于tablayout中显示的最大数-1时,会向左右滑动,指示器也会
  //跟这滑动,相对静止,否则指示器滑动,tab布局不移动
  if (position>=mmaxlinenum-1) {
   scrollcontent += leftcop - leftfortablayout;
   scrollto(scrollcontent, 0);
   //这里要重新layout
   update();
  }
  leftfortablayout = leftcop;
  invalidate();
 }
}

private void update() {
 for (int i = 0; i <mchildcount ; i++) {
  view v = getchildat(i);
  v.setleft(v.getleft()+scrollcontent);
 }
 requestlayout();
}

@override
public void onpageselected(int position) {

}

@override
public void onpagescrollstatechanged(int state) {
 switch (state){

 }
}

public void setmmaxlinenum(int mmaxlinenum) {
 this.mmaxlinenum = mmaxlinenum;
}

public void setontabselecterlistener(ontabselecterlistener montabselecterlistener) {
 this.montabselecterlistener = montabselecterlistener;
}

interface ontabselecterlistener{
 void selecter(int position,view view);
 }
}

好啦,就介绍这么多,还有待完善,继续封装,完成更强大的功能。

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