首页 文章 精选 留言 我的

精选列表

搜索[网站开发],共10000篇文章
优秀的个人博客,低调大师

【Android UI设计与开发】1.引导界面(一)ViewPager介绍和简单实现

1.ViewPager 实现效果图 2.ViewPager 实现功能 ViewPager类提供了多界面切换的新效果,新效果有如下特征: <1>当前显示一组界面中的其中一个界面; <2>当用户通过左右滑动界面时,当前的屏幕显示当前界面和下一个界面的一部分; <3>滑动结束后,界面自动跳转到当前选择的界面中。 3.ViewPager详细说明 android-support-v4.jar是谷歌官方给我们提供的一个兼容低版本安卓设备的软件包,里面包囊了只有在安卓3.0以上可以使用的api。而viewpager就是其中之一利用它,我们可以做很多事情,从最简单的导航,到页面菜单等等。那如何使用它呢,与ListView类似,我们也需要一个适配器,他就是PagerAdapter。 ViewPager对应官方文档地址为:http://developer.android.com/reference/android/support/v4/view/ViewPager.html 4、ViewPager的使用 分三个步骤来使用它: 1、在布局文件里加入该组件 <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" > 注意:这个组件是用来显示左右滑动的界面的,如果不加载xml布局文件,他是不会显示内容的 2、加载要显示的页卡 LayoutInflater lf = getLayoutInflater().from(this); view1 = lf.inflate(R.layout.layout1, null); view2 = lf.inflate(R.layout.layout2, null); view3 = lf.inflate(R.layout.layout3, null); viewList = new ArrayList<View>();// 将要分页显示的View装入数组中 viewList.add(view1); viewList.add(view2); viewList.add(view3); 3、在Activity里实例化ViewPager组件,并设置它的Adapter(就是PagerAdapter,方法与ListView一样的),在这里一般需要重写PagerAdapter。 public class MyViewPagerAdapter extends PagerAdapter { private List<View> mListViews; public MyViewPagerAdapter(List<View> mListViews) { this.mListViews = mListViews;//构造方法,参数是我们的页卡,这样比较方便。 } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(mListViews.get(position));//删除页卡 } @Override public Object instantiateItem(ViewGroup container, int position) {//这个方法用来实例化页卡 container.addView(mListViews.get(position), 0);//添加页卡 return mListViews.get(position); } @Override public int getCount() { return mListViews.size();//返回页卡的数量 } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0==arg1; } } ViewPager的适配器是PagerAdapter,它是基类提供适配器来填充页面ViewPager内部,你很可能想要使用一个更具体的实现,如FragmentPagerAdapter或FragmentStatePagerAdapter。在这里需要说明一下,其实ViewPager应该和Fragment一起使用,至少谷歌官方是这么想的,但是在3.0之下,我们没有必要这么做。下面要注意,当你实现一个PagerAdapter,你必须至少覆盖以下方法: instantiateItem(ViewGroup, int) destroyItem(ViewGroup, int, Object) getCount() isViewFromObject(View, Object) PagerAdapter对应的官方文档地址为:http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html 本文转自叶超Luka博客园博客,原文链接:http://www.cnblogs.com/yc-755909659/p/4282798.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

【Android游戏开发二十五】在Android上的使用《贝赛尔曲线》!

首先对于《赛贝尔曲线》不是很了解的童鞋,请自觉白度百科、google等等... 为了方便偷懒的童鞋,这里给个《贝赛尔曲线》百科地址,以及一段话简述《贝赛尔曲线》: 《贝赛尔曲线》白度百科快速地址:http://baike.baidu.com/view/4019466.htm 贝塞尔曲线又称贝兹曲线或贝济埃曲线,一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋; 上面这一段话其实就“线段像可伸缩的皮筋”这一句比较重要,也很容易理解; 至于贝赛尔曲线的实现,在Android中极其的简单,因为它是Android封装的一个方法,这个能不简单么。。。。。。只不过它隐藏的比较深,它隐藏于Path类中,方法如下: android.graphics.Path.quadTo(float x1, float y1, float x2, float y2) Since:API Level 1 此方参数解释: 第一个参数:操作点的x坐标 第二个参数:操作点的y坐标 第三个参数:结束点的x坐标 第四个参数:结束点的y坐标 从API中看出,赛贝尔曲线从API-1就开始支持了; 熟悉方法后,下面就来实现: SurfaceView框架不多讲,看过我博客的都应该知道的; 直接看MySurfaceView类,此类继承SurfaceView ,是游戏的主视图 这里为了更清晰的讲解:这里部分代码先不贴出来了,最后会整体贴出,当然源码也是免费在最后提供~ 首先是定义相关的成员变量: //贝赛尔曲线成员变量(起始点,控制(操作点),终止点,3点坐标) privateintstartX,startY,controlX,controlY,endX,endY; //Path privatePathpath; //为了不影响主画笔,这里绘制贝赛尔曲线单独用一个新画笔 privatePaintpaintQ; //随机库(让贝赛尔曲线更明显) privateRandomrandom; 本类构造函数: /** *SurfaceView初始化函数 */ publicMySurfaceView(Contextcontext){ super(context); ... //贝赛尔曲线相关初始化 path=newPath(); paintQ=newPaint(); paintQ.setAntiAlias(true); paintQ.setStyle(Style.STROKE); paintQ.setStrokeWidth(5); paintQ.setColor(Color.WHITE); random=newRandom(); ... } 接着我把绘制贝赛尔曲线封装一个方法了,函数如下: /** *绘制贝赛尔曲线 * *@paramcanvas主画布 */ publicvoiddrawQpath(Canvascanvas){ path.reset();//重置path //贝赛尔曲线的起始点 path.moveTo(startX,startY); //设置贝赛尔曲线的操作点以及终止点 path.quadTo(controlX,controlY,endX,endY); //绘制贝赛尔曲线(Path) canvas.drawPath(path,paintQ); } 最后是用户触屏监听函数以及逻辑函数: /** *触屏事件监听 */ @Override publicbooleanonTouchEvent(MotionEventevent){ endX=(int)event.getX(); endY=(int)event.getY(); returntrue; } /** *游戏逻辑 */ privatevoidlogic(){ if(endX!=0&&endY!=0){ //设置操作点为线段x/y的一半 controlX=random.nextInt((endX-startX)/2); controlY=random.nextInt((endY-startY)/2); } } 整个代码很easy~主要是贝赛尔函数的参数,尤其是操作点,操作点的各种不同可以实现不同的效果,这里我简单的统一的讲操作点设置成用户触屏点的x,y的一半,呵呵偷懒了~嘻嘻~ 我把贝赛尔的操作点写在了逻辑logic()函数中,不断的执行,并且每次利用nextInt函数得到随机的操作点,主要为了让其曲线不断的变化从而形成一个震动的曲线运动轨迹; ok,效果接图如下: 这里可能由于图片是静止的效果看起来不是很明显,大家可以运行源码来观察 ,好了~本节就这样吧;下面贴出整个MySurfaceView的源码:(最后有本项目的源码下载地址) package com.qpath; import java.util.Random; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Path; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; /** * 赛贝尔曲线 * @author Himi * */ public class MySurfaceView extends SurfaceView implements Callback, Runnable { private SurfaceHolder sfh; private Paint paint; private Thread th; private boolean flag; private Canvas canvas; public static int screenW, screenH; // -----------以上是SurfaceView游戏框架 // 贝赛尔曲线成员变量(起始点,控制(操作点),终止点,3点坐标) private int startX, startY, controlX, controlY, endX, endY; // Path private Path path; // 为了不影响主画笔,这里绘制贝赛尔曲线单独用一个新画笔 private Paint paintQ; // 随机库(让贝赛尔曲线更明显) private Random random; /** * SurfaceView初始化函数 */ public MySurfaceView(Context context) { super(context); sfh = this.getHolder(); sfh.addCallback(this); paint = new Paint(); paint.setColor(Color.WHITE); paint.setAntiAlias(true); setFocusable(true); // -----------以上是SurfaceView游戏框架 //贝赛尔曲线相关初始化 path = new Path(); paintQ = new Paint(); paintQ.setAntiAlias(true); paintQ.setStyle(Style.STROKE); paintQ.setStrokeWidth(5); paintQ.setColor(Color.WHITE); random = new Random(); } /** * SurfaceView视图创建,响应此函数 */ public void surfaceCreated(SurfaceHolder holder) { screenW = this.getWidth(); screenH = this.getHeight(); flag = true; // 实例线程 th = new Thread(this); // 启动线程 th.start(); // -----------以上是SurfaceView游戏框架 } /** * 游戏绘图 */ public void myDraw() { try { canvas = sfh.lockCanvas(); if (canvas != null) { canvas.drawColor(Color.BLACK); // -----------以上是SurfaceView游戏框架 drawQpath(canvas); } } catch (Exception e) { // TODO: handle exception } finally { if (canvas != null) sfh.unlockCanvasAndPost(canvas); } } /** * 绘制贝赛尔曲线 * * @param canvas 主画布 */ public void drawQpath(Canvas canvas) { path.reset();// 重置path // 贝赛尔曲线的起始点 path.moveTo(startX, startY); // 设置贝赛尔曲线的操作点以及终止点 path.quadTo(controlX, controlY, endX, endY); // 绘制贝赛尔曲线(Path) canvas.drawPath(path, paintQ); } /** * 触屏事件监听 */ @Override public boolean onTouchEvent(MotionEvent event) { endX = (int) event.getX(); endY = (int) event.getY(); return true; } /** * 游戏逻辑 */ private void logic() { if (endX != 0 && endY != 0) { // 设置操作点为线段x/y的一半 controlX = random.nextInt((endX - startX) / 2); controlY = random.nextInt((endY - startY) / 2); } } /** * 按键事件监听 */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return super.onKeyDown(keyCode, event); } public void run() { while (flag) { long start = System.currentTimeMillis(); myDraw(); logic(); long end = System.currentTimeMillis(); try { if (end - start < 50) { Thread.sleep(50 - (end - start)); } } catch (InterruptedException e) { e.printStackTrace(); } } } /** * SurfaceView视图状态发生改变,响应此函数 */ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } /** * SurfaceView视图消亡时,响应此函数 */ public void surfaceDestroyed(SurfaceHolder holder) { flag = false; } } 本章源码下载地址:http://www.himigame.com/android-game/386.html 本文转自 xiaominghimi 51CTO博客,原文链接:http://blog.51cto.com/xiaominghimi/606992,如需转载请自行联系原作者

优秀的个人博客,低调大师

【Android开发经验】LayoutInflater—— 你可能对它并不了解甚至错误使用

今天,看到了一篇文章讲LayoutInflater的使用方法。瞬间感觉自己对这个类确实不够了解,于是简单的看了下LayoutInflater类的源码。对这个类有了新的认识。 首先。LayoutInflater这个类是用来干嘛的呢? 我们最经常使用的便是LayoutInflater的inflate方法。这种方法重载了四种调用方式。分别为: 1.public View inflate(int resource, ViewGroup root) 2.public View inflate(int resource, ViewGroup root, boolean attachToRoot) 3.public View inflate(XmlPullParser parser, ViewGroup root) 4.public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) 这四种使用方式中。我们最经常使用的是第一种方式。inflate方法的主要作用就是将xml转换成一个View对象。用于动态的创建布局。尽管重载了四个方法。可是这四种方法终于调用的,还是第四种方式。 第四种方式也非常好理解,内部实现原理就是利用Pull解析器。对Xml文件进行解析,然后返回View对象。 我们以我们经常使用的第一种形式为例,你在重写BaseAdapter的getView方法的时候是否这样做过 public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = inflate(R.layout.item_row, null); } return convertView; } inflate方法有三个參数。各自是 1.resource布局的资源id 2.root填充的根视图 3.attachToRoot是否将载入的视图绑定到根视图中 在这个样例中,我们将root參数设为空,功能确实实现了。可是这里还隐藏着一个隐患。这样的方式并非inflate正确的使用姿势,以下我们通过一个Demo,来说一下这样使用造成的弊端。 首先,我们建立一个这样的项目 这里三个界面,一个主界面,两个測试界面,布局文件里。主界面仅仅负责界面跳转,两个測试界面都是一个简单的Listview,item布局显示效果例如以下 相应的布局文件例如以下 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="60dp" android:background="@android:color/holo_orange_light" android:gravity="center" android:orientation="vertical" > <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="11" android:textColor="@android:color/black" android:textSize="22sp" /> </LinearLayout> OneActivity的代码例如以下 public class OneActivity extends Activity { private ListView list1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_one); list1 = (ListView) findViewById(R.id.list1); list1.setAdapter(new MyAdapter(this)); } private class MyAdapter extends BaseAdapter { private LayoutInflater inflater; MyAdapter(Context context) { inflater = LayoutInflater.from(context); } @Override public int getCount() { return 20; } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = inflater.inflate(R.layout.item_list, null); } TextView tv = (TextView) convertView.findViewById(R.id.tv); tv.setText(position+""); return convertView; } } } TwoActivity的代码例如以下 public class TwoActivity extends Activity { private ListView list2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_two); list2 = (ListView) findViewById(R.id.list2); list2.setAdapter(new MyAdapter(this)); } private class MyAdapter extends BaseAdapter { private LayoutInflater inflater; MyAdapter(Context context) { inflater = LayoutInflater.from(context); } @Override public int getCount() { return 20; } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = inflater.inflate(R.layout.item_list, parent,false); } TextView tv = (TextView) convertView.findViewById(R.id.tv); tv.setText(position + ""); return convertView; } } } 两个文件最关键的差别就一句话。 在getView方法中,OneActivity是 convertView = inflater.inflate(R.layout.item_list, null); 在getView方法中,TwoActivity是 convertView = inflater.inflate(R.layout.item_list, parent,false); 我们先看一下显示效果。再说两者的差别 OneActivity效果 TwoActivity的显示效果 我们能够非常明显的看出来,使用第一种方式,根布局的高度设置60dp没有起作用,系统还是依照包裹内容的方式载入的,为什么会产生这样的效果呢?我们从须要inflate方法的源码中找一下答案。 首先,方式一的源码实现 public View inflate(XmlPullParser parser, ViewGroup root) { return inflate(parser, root, root != null); } 当我们使用方式一,而且第二个參数传入null的时候,默认调用的是以下的方法,而且attachToRoot是false public View inflate(int resource, ViewGroup root, boolean attachToRoot) { if (DEBUG) System.out.println("INFLATING from resource: " + resource); XmlResourceParser parser = getContext().getResources().getLayout(resource); try { return inflate(parser, root, attachToRoot); } finally { parser.close(); } } 在这一个方法中,pull解析器将资源id转化成XmlResourceParser对象,又传给了第四种方式,所以我们须要重点看的还是第四种方式是怎样实现的 public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) { synchronized (mConstructorArgs) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate"); final AttributeSet attrs = Xml.asAttributeSet(parser); Context lastContext = (Context)mConstructorArgs[0]; mConstructorArgs[0] = mContext; View result = root; try { // Look for the root node. int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { // Empty } if (type != XmlPullParser.START_TAG) { throw new InflateException(parser.getPositionDescription() + ": No start tag found!"); } final String name = parser.getName(); if (DEBUG) { System.out.println("**************************"); System.out.println("Creating root view: " + name); System.out.println("**************************"); } if (TAG_MERGE.equals(name)) { if (root == null || !attachToRoot) { throw new InflateException("<merge /> can be used only with a valid " + "ViewGroup root and attachToRoot=true"); } rInflate(parser, root, attrs, false); } else { // Temp is the root view that was found in the xml View temp; if (TAG_1995.equals(name)) { temp = new BlinkLayout(mContext, attrs); } else { temp = createViewFromTag(root, name, attrs); } ViewGroup.LayoutParams params = null; if (root != null) { if (DEBUG) { System.out.println("Creating params from root: " + root); } // Create layout params that match root, if supplied params = root.generateLayoutParams(attrs); if (!attachToRoot) { // Set the layout params for temp if we are not // attaching. (If we are, we use addView, below) temp.setLayoutParams(params); } } if (DEBUG) { System.out.println("-----> start inflating children"); } // Inflate all children under temp rInflate(parser, temp, attrs, true); if (DEBUG) { System.out.println("-----> done inflating children"); } // We are supposed to attach all the views we found (int temp) // to root. Do that now. if (root != null && attachToRoot) { root.addView(temp, params); } // Decide whether to return the root that was passed in or the // top view found in xml. if (root == null || !attachToRoot) { result = temp; } } } catch (XmlPullParserException e) { InflateException ex = new InflateException(e.getMessage()); ex.initCause(e); throw ex; } catch (IOException e) { InflateException ex = new InflateException( parser.getPositionDescription() + ": " + e.getMessage()); ex.initCause(e); throw ex; } finally { // Don't retain static reference on context. mConstructorArgs[0] = lastContext; mConstructorArgs[1] = null; } Trace.traceEnd(Trace.TRACE_TAG_VIEW); return result; } } 代码比較长,我们重点关注以下的代码 if (root != null) { if (DEBUG) { System.out.println("Creating params from root: " + root); } // Create layout params that match root, if supplied params = root.generateLayoutParams(attrs); if (!attachToRoot) { // Set the layout params for temp if we are not // attaching. (If we are, we use addView, below) temp.setLayoutParams(params); } } 这些代码的意思就是,当我们传进来的root參数不是空的时候,而且attachToRoot是false的时候,也就是上面的TwoActivity的实现方式的时候,会给temp设置一个LayoutParams參数。那么这个temp又是干嘛的呢? <pre name="code" class="java">// We are supposed to attach all the views we found (int temp) // to root. Do that now. if (root != null && attachToRoot) { root.addView(temp, params); } // Decide whether to return the root that was passed in or the // top view found in xml. if (root == null || !attachToRoot) { result = temp; } 如今应该明确了吧。当我们传进来的root不是null,而且第三个參数是false的时候。这个temp就被增加到了root中。而且把root当作终于的返回值返回了。而当我们设置root为空的时候,没有设置LayoutParams參数的temp对象。作为返回值返回了。 因此,我们能够得出以下的结论: 1.若我们採用convertView = inflater.inflate(R.layout.item_list, null);方式填充视图。item布局中的根视图的layout_XX属性会被忽略掉。然后设置成默认的包裹内容方式 2.假设我们想保证item的视图中的參数不被改变,我们须要使用convertView = inflater.inflate(R.layout.item_list, parent,false);这样的方式进行视图的填充 3.除了使用这样的方式,我们还能够设置item布局的根视图为包裹内容,然后设置内部控件的高度等属性。这样就不会改动显示方式了。 最后,给出那篇文章的链接http://blog.jobbole.com/72156/大家能够去看看 本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5230670.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Java微服务开发指南 -- 集群管理、失败转移和负载均衡的实践

集群管理、失败转移和负载均衡的实践 在前一章节中,我们快速的介绍了集群管理、Linux容器,接下来让我们使用这些技术来解决微服务的伸缩性问题。作为参考,我们使用的微服务工程来自于第二、第三和第四章节(Spring Boot、Dropwizard和WildFly Swarm)中的内容,接下来的步骤都适合上述三款框架。 开始 我们需要将微服务打包成为Docker镜像,最终将其部署到Kubernetes,首先进入到项目工程hola-springboot,然后启动jboss-forge,然后安装fabric8插件,这个插件使我们安装maven插件变得非常容易。 $ cd ~/Documents/workspace/microservices-camp/ weipengktekiMBP:microservices-camp weip

优秀的个人博客,低调大师

【Android开发坑系列】之经常被忽略的背景图片内存泄露

我们平时设置图片的时候,几乎都忘记回收老的(背景)图片,比如: TextView.setBackgroundDrawable() TextView.setBackgroundResource() ImageView.setImageDrawable() ImageView.setImageResource() ImageView.setImageBitmap() 这样造成内存浪费,积少成多,整个软件可能浪费不少内存。 如果记得优化,整个软件的内存占用会有10%~20%的下降。 // 获得ImageView当前显示的图片 Bitmap bitmap1 = ((BitmapDrawable) imageView.getBackground()).getBitmap(); Bitmap bitmap2 = Bitmap.createBitmap(bitmap1, 0, 0, bitmap1.getWidth(),bitmap1.getHeight(), matrix, true); // 设置新的背景图片 imageView.setBackgroundDrawable(new BitmapDrawable(bitmap2)); // bitmap1确认即将不再使用,强制回收,这也是我们经常忽略的地方 if (!bitmap1.isRecycled()) { bitmap1.recycle(); } 看上面的代码,设置新的背景之后,老的背景确定不再使用,则应该回收。 封装如下(仅针对setBackgroundXXX做了封装,其他的原理类同): /** * 给view设置新背景,并回收旧的背景图片<br> * <font color=red>注意:需要确定以前的背景不被使用</font> * * @param v */ @SuppressWarnings("deprecation") public static void setAndRecycleBackground(View v, int resID) { // 获得ImageView当前显示的图片 Bitmap bitmap1 = null; if (v.getBackground() != null) { try { //若是可转成bitmap的背景,手动回收 bitmap1 = ((BitmapDrawable) v.getBackground()).getBitmap(); } catch (ClassCastException e) { //若无法转成bitmap,则解除引用,确保能被系统GC回收 v.getBackground().setCallback(null); } } // 根据原始位图和Matrix创建新的图片 v.setBackgroundResource(resID); // bitmap1确认即将不再使用,强制回收,这也是我们经常忽略的地方 if (bitmap1 != null && !bitmap1.isRecycled()) { bitmap1.recycle(); } } /** * 给view设置新背景,并回收旧的背景图片<br> * <font color=red>注意:需要确定以前的背景不被使用</font> * * @param v */ @SuppressWarnings("deprecation") public static void setAndRecycleBackground(View v, BitmapDrawable imageDrawable) { // 获得ImageView当前显示的图片 Bitmap bitmap1 = null; if (v.getBackground() != null) { try { //若是可转成bitmap的背景,手动回收 bitmap1 = ((BitmapDrawable) v.getBackground()).getBitmap(); } catch (ClassCastException e) { //若无法转成bitmap,则解除引用,确保能被系统GC回收 v.getBackground().setCallback(null); } } // 根据原始位图和Matrix创建新的图片 v.setBackgroundDrawable(imageDrawable); // bitmap1确认即将不再使用,强制回收,这也是我们经常忽略的地方 if (bitmap1 != null && !bitmap1.isRecycled()) { bitmap1.recycle(); } } 本文转自Kai的世界,道法自然博客园博客,原文链接:http://www.cnblogs.com/kaima/p/3497525.html,如需转载请自行联系原作者。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册