课程咨询: 400-996-5531 / 投诉建议: 400-111-8989

认识达内从这里开始

认真做教育 专心促就业

达内太原it培训微信编程效果实现过程
  • 发布:佚名
  • 来源:推酷
  • 时间:2016-09-21 10:50

微信相信大家都不陌生,作为一款社交软件,他慢慢的潜入了我们的生活之中,许多人的休闲时间很大一部分都分配给了微信,那么,大家有没有对微信的编程代码是如何实现某些效果有所关注呢?

天天使用微信,作为一个android developer,当然会对微信的底部tab感兴趣,刚好工作中要开发一个bbs客户端,gui也要求实现一个类似微信底部tab效果的控件, 开始在网上狂搜一通,也找到了类似的东西(至于是哪位大神的,我已经忘了连接,这里就不详述了),进过自己进一步的封装,自认为完美的实现了gui的设计需求, 然而现在在回想实现的细节,却很难想起其中的关键点,于是乎,决定自己重新写一个,加深自定义ViewGroup和自定义View。

该控件的技术难点:

如果通过监听ViewPager的滑动来实现Tab切换的渐变效果

当然对我来说自己重新实现就不止上述一个难点了,下面就让我们还是从源代码中逐步分析如何实现自定义的TabSelectorLayout

实现过程

上述技术难点如何解决

对于Tab,显示状态只有两个,一个select,一个normal,大家仔细观察微信的渐变效果,其实就是在滑动page的时候,选择的item就是select状态逐渐显示, 而normal状态逐渐消失,而失去select状态的item,与之相反;那么我们就可以通过控制两个状态的drawable的alpha值(状态之间属于”补集”)来实现状态切换 的渐变效果

定义View的属性

[attrs.xml]

定义Tab属性类

public static final class Tab { //TabSelectorLayout嵌套类

Drawable normalDrawable; //自然状态图片

Drawable selectDrawable; //选中状态的图片

String title; //文字

int position; //tab的位置

private Tab() { // TabSelectorLayout外部无法创建该类的对象

}

Tab setPosition(int position) { //TabSelectorLayout外部无法访问该方法

this.position = position;

return this;

}

public int getPosition() {

return position;

}

public Tab setTitle(String title) {

this.title = title;

return this;

}

public Tab setNormalDrawable(Drawable d) {

normalDrawable = d;

return this;

}

public Tab setSelectDrawable(Drawable d) {

selectDrawable = d;

return this;

}

}

TabSelectorLayout的属性

private ViewPager viewPager; //和关联的ViewPager

private int textSize = 12; //文字大小

private int drawablePadding = 10; //drawable和文字之间的距离

private int normalTextColor, selectTextColor; //文字两种状态的颜色值

构造方法(解析xml属性)

public TabSelectorLayout(Context context) {

super(context);

}

public TabSelectorLayout(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public TabSelectorLayout(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

TypedArray array = null;

try {

array = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.TabSelectorLayout, defStyleAttr, 0);

int count = array.getIndexCount();

for (int i = 0; i < count; i++) {

final int index = array.getIndex(i);

if (index == R.styleable.TabSelectorLayout_normalTextColor) {

normalTextColor = array.getColor(index, Color.BLACK);

} else if (index == R.styleable.TabSelectorLayout_selectTextColor) {

selectTextColor = array.getColor(index, Color.BLACK);

} else if (index == R.styleable.TabSelectorLayout_drawablePadding) {

drawablePadding = array.getDimensionPixelSize(index, 10);

} else if (index == R.styleable.TabSelectorLayout_android_textSize) {

textSize = array.getDimensionPixelSize(index,

(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, textSize, getResources().getDisplayMetrics()));

}

}

Log.d(TAG, "normalTextColor = " + normalTextColor + " drawablePadding = " + drawablePadding + " textSize = " + textSize);

} finally {

if (array != null) {

array.recycle();

}

}

}

提供获得Tab对象的方法

public static Tab newTab() {

return new Tab();

}

将初始化好的Tab添加到TabSelectorLayout中

public int addTab(final Tab tab) { //返回添加tab的posion

//参数判断

if (tab == null) {

throw new NullPointerException("tab is null");

}

if (tab.title == null || tab.selectDrawable == null || tab.normalDrawable == null) {

throw new IllegalArgumentException("some argument is null");

}

final TabView tabView = new TabView(getContext()); //new 出显示的TabView

tabView.attach(tab); //关联tab到TabView中

tabView.setOnClickListener(new OnClickListener() { //tab的click监听,切换ViewPager的显示

@Override

public void onClick(View v) {

viewPager.setCurrentItem(tab.getPosition(), false); //切换不滚动

}

});

addView(tabView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

tab.setPosition(indexOfChild(tabView)); //设置tab的position

return tab.position;

}

重写addView对添加的child做以下限制

@Override

public void addView(View child, int index, ViewGroup.LayoutParams params) { //只能添加TabView

if (child instanceof TabView) {

super.addView(child, index, params);

} else {

throw new IllegalArgumentException("child is not TabView");

}

}

关联ViewPager

public void bindViewPager(ViewPager pager) {

//参数处理

if (pager == null)

throw new NullPointerException("pager is null");

if (viewPager == pager)

return;

if (viewPager != null) //remove对上个ViewPager的监听

viewPager.removeOnPageChangeListener(pageChangeListener);

//ViewPager的Adapter数据判读

PagerAdapter adapter = pager.getAdapter();

if (adapter == null)

throw new IllegalArgumentException("pager not set adapter");

if (adapter.getCount() != getChildCount())

throw new IllegalArgumentException("pager count is not equeals tab count");

pager.addOnPageChangeListener(pageChangeListener); //添加OnPageChangeListener

viewPager = pager;

setCurrentItem(viewPager.getCurrentItem()); //设置显示的Tab

}

OnPageChangeListener的实现,给TabView传入ViewPager滑动变化数据

private ViewPager.OnPageChangeListener pageChangeListener = new ViewPager.SimpleOnPageChangeListener() {

@Override

public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

TabView cur = (TabView) getChildAt(position);

if (positionOffset > 0) {

cur.setTabOffSet(1 - positionOffset);

TabView next = (TabView) getChildAt(position + 1);

next.setTabOffSet(positionOffset);

} else {

cur.setTabOffSet(1 - positionOffset);

}

}

@Override

public void onPageSelected(int position) {

setCurrentItem(position);

}

};

切换Tab方法

public void setCurrentItem(int item) {

final int count = getChildCount();

for (int i = 0; i < count; i++) {

TabView child = (TabView) getChildAt(i);

child.setSelected(item == i); //修改TabView的选中状态

}

}

万年不变的onMeasure方法

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int width = MeasureSpec.getSize(widthMeasureSpec);

int height = MeasureSpec.getSize(heightMeasureSpec);

final int count = getChildCount();

int childWidth = (width - getPaddingLeft() - getPaddingRight()) / count; //每个child的宽度一样

int maxChildHeight = 0; //所有child中最高的值

for (int i = 0; i < count; i++) {

final View child = getChildAt(i);

if (child.getVisibility() != GONE) {

//测量child,精确child的宽度,设定child的最大高度

child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));

int h = child.getMeasuredHeight();

int w = child.getMeasuredWidth();

maxChildHeight = maxChildHeight > h ? maxChildHeight : h;

}

}

int actionBarHeight = getActionBarHeight(); //默认Layout的高度是ActionBar的高度

int h = actionBarHeight > maxChildHeight ? actionBarHeight : maxChildHeight;

setMeasuredDimension(width, h + getPaddingTop() + getPaddingBottom());

}

获取actionBar的高度

private int getActionBarHeight() {

TypedValue tv = new TypedValue();

if (getContext().getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))

return TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());

return 0;

}

必须实现的onLayout方法

@Override

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

final int count = getChildCount();

int lefPos = getPaddingLeft(); //child的left位置

final int parentTop = getPaddingTop();

final int parentBottom = bottom - top - getPaddingBottom();

final int parentHeight = parentBottom - parentTop;

final Rect childRect = new Rect(); //child的显示矩阵

for (int i = 0; i < count; i++) {

final View child = getChildAt(i);

if (child.getVisibility() != GONE) {

final LayoutParams lp = (LayoutParams) child.getLayoutParams();

final int width = child.getMeasuredWidth();

final int height = child.getMeasuredHeight();

lefPos += lp.leftMargin; //变化下一个child的left

childRect.left = lefPos;

childRect.top = (parentHeight - height) / 2;

childRect.bottom = childRect.top + height;

childRect.right = childRect.left + width;

// Use the child's gravity and size to determine its final

// frame within its container.

//Gravity.apply(lp.gravity, width, height, mTmpContainerRect, mTmpChildRect);

child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom); //layout child

lefPos += width; //变化下一个child的left

lefPos += lp.rightMargin; //变化下一个child的left

}

}

定义TabView

private class TabView extends View { //私有内部类

TabView属性

private int normalAlpha = 255; //自然状态下的alpha

private int viewWidth; //TabView宽度

private int viewHeight;//TabView高度

private final Paint textNormalPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.SUBPIXEL_TEXT_FLAG); //自然状态text画笔

private final Paint textSelectPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.SUBPIXEL_TEXT_FLAG);//选中状态text画笔

private final Rect boundText = new Rect(); //text的bound

private Tab tab; //关联的tab

TabView属性初始化

private void initText() {

textNormalPaint.setColor(normalTextColor);

textNormalPaint.setTextSize(textSize);

textSelectPaint.setColor(selectTextColor);

textSelectPaint.setTextSize(textSize);

}

获得指定字体大小text的显示矩阵

private void measureText() {

textNormalPaint.getTextBounds(tab.title, 0, tab.title.length(), boundText);

}

通过监听到的ViewPager滑动变化来修改显示的alpha

void setTabOffSet(float offSet) {

normalAlpha = (int) (255 - offSet * 255);

invalidate();

}

重新setSelected方法,来修改显示的alpha

@Override

public void setSelected(boolean selected) {

normalAlpha = selected ? 0 : 255;

super.setSelected(selected);

}

TabView的onMeasure方法

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int width = MeasureSpec.getSize(widthMeasureSpec);

int widthMode = MeasureSpec.getMode(widthMeasureSpec);

int height = MeasureSpec.getSize(heightMeasureSpec);

int heightMode = MeasureSpec.getMode(heightMeasureSpec);

int w = 0, h = 0;

measureText();//获得指定字体大小text的显示矩阵

//显示内容的最大宽度

int contentWidth = Math.max(boundText.width(), Math.max(tab.normalDrawable.getIntrinsicWidth(), tab.selectDrawable.getIntrinsicWidth()));

//期望的宽度

int desiredWidth = getPaddingLeft() + getPaddingRight() + contentWidth;

switch (widthMode) {

case MeasureSpec.AT_MOST:

w = Math.min(width, desiredWidth);

break;

case MeasureSpec.EXACTLY: //实现的ViewGroup中已经指定精确TabView的宽度

w = width;

break;

case MeasureSpec.UNSPECIFIED:

w = desiredWidth;

break;

}

//获得显示内容的高度,注意这里计算text的高度使用了Paint的getFontSpacing()方法,原因可以参考文后资料

int contentHeight = (int) (textNormalPaint.getFontSpacing() + Math.max(tab.normalDrawable.getIntrinsicHeight(), tab.selectDrawable.getIntrinsicHeight()) + drawablePadding);

//期望的最大高度

int desiredHeight = getPaddingTop() + getPaddingBottom() + contentHeight;

switch (heightMode) {

case MeasureSpec.AT_MOST:

h = Math.min(height, desiredHeight);

break;

case MeasureSpec.EXACTLY:

h = height;

break;

case MeasureSpec.UNSPECIFIED:

h = height;

break;

}

setMeasuredDimension(w, h);

viewWidth = getMeasuredWidth();

viewHeight = getMeasuredHeight();

}

TabView的onDraw方法

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

drawNoramalBitmap(canvas);

drawSelectBitmap(canvas);

drawText(canvas);

}

TabView的自然状态drawable的绘制

private void drawNoramalBitmap(Canvas canvas) {

int width = tab.normalDrawable.getIntrinsicWidth();

int height = tab.normalDrawable.getIntrinsicHeight();

int left = (viewWidth - width) / 2;

int top = (viewHeight - height - boundText.height() - drawablePadding) >> 1;

tab.normalDrawable.setBounds(left, top, left + width, top + height);

tab.normalDrawable.setAlpha(normalAlpha); //修改绘制drawable的alpha

tab.normalDrawable.draw(canvas);

}

TabView的选中状态drawable的绘制

private void drawSelectBitmap(Canvas canvas) {

int width = tab.selectDrawable.getIntrinsicWidth();

int height = tab.selectDrawable.getIntrinsicHeight();

int left = (viewWidth - width) / 2;

int top = (viewHeight - height - boundText.height() - drawablePadding) >> 1;

tab.selectDrawable.setBounds(left, top, left + width, top + height);

tab.selectDrawable.setAlpha(255 - normalAlpha); //修改绘制drawable的alpha

tab.selectDrawable.draw(canvas);

}

TabView的text的绘制

private void drawText(Canvas canvas) {

int drawableHeight = Math.max(tab.normalDrawable.getIntrinsicHeight(), tab.selectDrawable.getIntrinsicHeight());

float x = (viewWidth - boundText.width()) / 2.0f;

float y = (viewHeight + drawableHeight + boundText.height() + drawablePadding) >> 1;

textNormalPaint.setAlpha(normalAlpha); //修改绘制text自然状态的alpha

canvas.drawText(tab.title, x, y, textNormalPaint);

textSelectPaint.setAlpha(255 - normalAlpha); //修改绘制text选中状态的alpha

canvas.drawText(tab.title, x, y, textSelectPaint);

}

如何使用

使用的xml代码

android:id="@+id/tabselectorlayout"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_alignParentBottom="true"

app:selectTextColor="@android:color/holo_green_dark"

app:normalTextColor="@android:color/darker_gray"

app:drawablePadding="5dp"

android:textSize="13sp"/>

使用的java代码

//首先获得TabSelectorLayout对象

mTabSelectorLayout = (TabSelectorLayout) findViewById(R.id.tabselectorlayout);

...

//添加tab

mTabSelectorLayout.addTab(TabSelectorLayout.newTab()

.setNormalDrawable(resources.getDrawable(R.drawable.ic_tab_moment))

.setSelectDrawable(resources.getDrawable(R.drawable.ic_tab_moment_select))

.setTitle("moment"));

...

//和ViewPager绑定

mTabSelectorLayout.bindViewPager(mViewPager);

文章感想

写完本文就觉得自己啰嗦了,总想将所有的内容都写出来,哪怕再简单的东西,大量的代码对读者来说都很简单,但我只想展示自己实现这个控件一步步的过程, 期望自己以后的文章尽量提升blog的水平吧

达内时代科技集团致力于培养面向电信和金融领域的Java、C++、C#/.Net、3G/Android、3G/IOS、PHP、嵌入式、软件测试、UID、网络营销、网络工程、会计、UED、web、Unity3D、大数据、童程童美等17大方向中高端软件人才课程与少儿教育课程。选择达内运城it培训,不再孤军奋战,轻轻松松做IT高薪白领。运城达内培训带领有明确目标的学子迈向成功之路!想找工作的求职者可以加QQ:3373924515(太原达内就业服务部)咨询了解。

<  上一篇:太原it培训电商平台的新形式运行模式选择
下一篇:达内太原it培训ui设计师报价指南攻略  >
相关推荐
最新资讯
免费试听课程
  • 全部课程
  • IT课程
  • 设计课程
  • 运营课程
Free courses
最新开班时间
  • 北京
  • 上海
  • 广州
  • 深圳
  • 南京
  • 成都
  • 武汉
  • 西安
  • 青岛
  • 天津
  • 杭州
  • 重庆
  • 哈尔滨
  • 济南
  • 沈阳
  • 合肥
  • 郑州
  • 长春
  • 苏州
  • 长沙
  • 昆明
  • 太原
  • 无锡
  • 石家庄
  • 南宁
  • 佛山
  • 珠海
  • 宁波
  • 保定
  • 呼和浩特
  • 洛阳
  • 烟台
  • 运城
  • 潍坊
  • 开课名称
  • 开班时间
  • 抢座
  • 咨询
  • 开课名称
  • 开班时间
  • 抢座
  • 咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 云计算全栈开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 人工智能工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 数据分析与商业智能
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AGI商业设计变现
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 新媒体电商运营
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 云计算全栈开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 云计算全栈开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 云计算全栈开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AGI商业设计变现
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 新媒体电商运营
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 云计算全栈开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AGI商业设计变现
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 新媒体电商运营
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 云计算全栈开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 云计算全栈开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 数据分析与商业智能
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AGI商业设计变现
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 新媒体电商运营
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 新媒体电商运营
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AGI商业设计变现
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 云计算全栈开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AGI商业设计变现
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 新媒体电商运营
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 云计算全栈开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 新媒体电商运营
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AGI商业设计变现
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AGI商业设计变现
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 云计算全栈开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AGI商业设计变现
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • Java全链路开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AGI商业设计变现
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AGI商业设计变现
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 网络安全工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • C++物联网工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 软件测试工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • AI大模型全栈工程师
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • 鸿蒙原生应用开发
    • 9月29日
    • 火热抢座中
    • 立即咨询
    • VFX商业视效设计
    • 9月29日
    • 火热抢座中
    • 立即咨询
预约申请试听课
收起