当前位置: 移动技术网 > IT编程>移动开发>Android > Android自定义TabLayout效果

Android自定义TabLayout效果

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

孙柏龄,食蝇花,达贝妮淘宝

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

这里是四个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);
 }
}

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

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

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

相关文章:

验证码:
移动技术网