首页 文章 精选 留言 我的

精选列表

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

Android开发22——广播接收者BroadcastReceiver的原理和注册方式

一、广播机制的基本概念 当某个事件产生时(如一条短信发来或一个电话打来),android操作系统会把这个事件广播给所有注册的广播接收者,需要处理这个事件的广播接收者进行处理。其实这就是日常生活中的广播。发生一个新闻后,广播电台会广播这个新闻给打开收音机的人,对这个新闻感兴趣的人会关注,可能会拿笔记下。新闻就是事件,广播电台就是android系统,打开收音机的人就是广播接收者,感兴趣的人就是需要处理该事件的广播接收者,拿笔记下就是对该事件进行的操作。 二、广播的分类——普通广播和有序广播 ①普通广播:完全异步,逻辑上可以被任何广播接收者接收到。优点是效率较高。缺点是一个接收者不能将处理结果传递给下一个接收者,并无法终止广播intent的传播。 ②有序广播:按照被接收者的优先级顺序,在被接收者中一次传播。比如有三个广播接收者A,B,C,优先级是A > B > C。那这个消息先传给A,再传给B,最后传给C。每个接收者有权中终止广播,比如B终止广播,C就无法接收到。此外A接收到广播后可以对结果对象进行操作,当广播传给B时,B可以从结果对象中取得A存入的数据。如系统收到短信发出的广播就是有序广播。 三、注册广播接收者的两种方式 ①在AndroidManifest.xml中注册 在配置文件中注册的接收者的特点是即使应用程序已被关闭,该接收者依然可接受它感兴趣的广播,比如手机电池电量的广播接收者,没有必要将某个程序开启。下面的例子1、2广播接收者会接收到拨打电话的广播。 <applicationandroid:icon="@drawable/icon"android:label="@string/app_name"> <activityandroid:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <!--广播接收者1--> <receiverandroid:name=".BroadcastReceiver1"> <intent-filter> <actionandroid:name="android.intent.action.CALL"></action> </intent-filter> </receiver> <!--广播接收者2--> <receiverandroid:name=".BroadcastReceiver2"> <intent-filter> <actionandroid:name="android.intent.action.CALL"></action> </intent-filter> </receiver> <!--广播接收者3--> <receiverandroid:name=".BroadcastReceiver3"> <intent-filter> <actionandroid:name="android.intent.action.PICK"></action> </intent-filter> </receiver> </application> /** *模拟拨打电话广播 * *@author徐越 * */ publicclassMainActivityextendsActivity { @Override publicvoidonCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Intentintent=newIntent(); intent.setAction("android.intent.action.CALL"); this.sendBroadcast(intent); } } /** *每次接收广播都会生成新的BroadcastReceiver1,当处理完onReceive方法后就不会再被使用 *再次接收就在生成新的BroadcastReceiver1对象 * *@author徐越 * */ publicclassBroadcastReceiver1extendsandroid.content.BroadcastReceiver { publicBroadcastReceiver1() { Log.i("xy_Receiver","construtor1"); } @Override publicvoidonReceive(Contextcontext,Intentintent) { Log.i("xy_Receiver","onReceive1"); } } /** *广播接收者2 * *@author徐越 * */ publicclassBroadcastReceiver2extendsandroid.content.BroadcastReceiver { publicBroadcastReceiver2() { Log.i("xy_Receiver","construtor2"); } @Override publicvoidonReceive(Contextcontext,Intentintent) { Log.i("xy_Receiver","onReceive2"); } } /** *广播接收者3 * *@author徐越 * */ publicclassBroadcastReceiver3extendsandroid.content.BroadcastReceiver { publicBroadcastReceiver3() { Log.i("xy_Receiver","construtor3"); } @Override publicvoidonReceive(Contextcontext,Intentintent) { Log.i("xy_Receiver","onReceive3"); } } ②在Activity中注册 在Activity中绑定接收者必须依附该应用程序存在,或者一个BroadcastReceiver用于更新UI,就没有必要再程序关闭时接收者还运行,故无需在AndroidManifest.xml中注册而可以放在Activity中注册。 /** *Activity中注册广播接收者 * *@author徐越 * */ publicclassMainActivityextendsActivity { privateBroadcastReceiverreceiver; privatestaticfinalStringCALL_ACTION="android.intent.action.CALL"; @Override publicvoidonCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } /** *模拟发送一个电话的广播 * *@paramv */ publicvoidsendBroadCast(Viewv) { Intentintent=newIntent(); intent.setAction("android.intent.action.CALL"); this.sendBroadcast(intent); } publicvoidbindReceiver(Viewv) { receiver=newBroadcastReceiver(); IntentFilterintentFilter=newIntentFilter(); intentFilter.addAction(CALL_ACTION); this.registerReceiver(receiver,intentFilter); } publicvoidunBindReceiver(Viewv) { this.unregisterReceiver(receiver); } } publicclassBroadcastReceiverextendsandroid.content.BroadcastReceiver { @Override publicvoidonReceive(Contextcontext,Intentintent) { Log.i("xy","receiver"); } } 本文转自IT徐胖子的专栏博客51CTO博客,原文链接http://blog.51cto.com/woshixy/1097197如需转载请自行联系原作者 woshixuye111

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

Android UI开发第十六篇——分享一个popuwindow实例

PopupWindow在android.widget包下,弹出窗口的形式展示。官方文档对该控件的描述是:“一个弹出窗口控件,可以用来显示任意视图(View),而且会浮动在当前 活动(activity)的顶部”。PopupWindow可以让我们实现多种自定义控件,例如:menu、alertdialog等弹窗似的View。 实现中使用的PopupWindow。这里做了简单封装,其中有三个类组成:PopuItem、PopuJar、PopupWindows。 publicclassPopuItem{ privateDrawableicon; privateBitmapthumb; privateStringtitle; privateintactionId=-1; privatebooleanselected; privatebooleansticky; /** *Constructor * *@paramactionIdActionidforcasestatements *@paramtitleTitle *@paramiconIcontouse */ publicPopuItem(intactionId,Stringtitle,Drawableicon){ this.title=title; this.icon=icon; this.actionId=actionId; } /** *Constructor */ publicPopuItem(){ this(-1,null,null); } /** *Constructor * *@paramactionIdActionidoftheitem *@paramtitleTexttoshowfortheitem */ publicPopuItem(intactionId,Stringtitle){ this(actionId,title,null); } /** *Constructor * *@paramicon{@linkDrawable}actionicon */ publicPopuItem(Drawableicon){ this(-1,null,icon); } /** *Constructor * *@paramactionIdActionIDofitem *@paramicon{@linkDrawable}actionicon */ publicPopuItem(intactionId,Drawableicon){ this(actionId,null,icon); } /** *Setactiontitle * *@paramtitleactiontitle */ publicvoidsetTitle(Stringtitle){ this.title=title; } /** *Getactiontitle * *@returnactiontitle */ publicStringgetTitle(){ returnthis.title; } /** *Setactionicon * *@paramicon{@linkDrawable}actionicon */ publicvoidsetIcon(Drawableicon){ this.icon=icon; } /** *Getactionicon *@return{@linkDrawable}actionicon */ publicDrawablegetIcon(){ returnthis.icon; } /** *Setactionid * *@paramactionIdActionidforthisaction */ publicvoidsetActionId(intactionId){ this.actionId=actionId; } /** *@returnOuractionid */ publicintgetActionId(){ returnactionId; } /** *Setstickystatusofbutton * *@paramstickytrueforsticky,popupsendseventbutdoesnotdisappear */ publicvoidsetSticky(booleansticky){ this.sticky=sticky; } /** *@returntrueifbuttonissticky,menustaysvisibleafterpress */ publicbooleanisSticky(){ returnsticky; } /** *Setselectedflag; * *@paramselectedFlagtoindicatetheitemisselected */ publicvoidsetSelected(booleanselected){ this.selected=selected; } /** *Checkifitemisselected * *@returntrueorfalse */ publicbooleanisSelected(){ returnthis.selected; } /** *Setthumb * *@paramthumbThumbimage */ publicvoidsetThumb(Bitmapthumb){ this.thumb=thumb; } /** *Getthumbimage * *@returnThumbimage */ publicBitmapgetThumb(){ returnthis.thumb; } } public class PopuJar extends PopupWindows implements OnDismissListener { private View mRootView; private ImageView mArrowUp; private ImageView mArrowDown; private LayoutInflater mInflater; private ViewGroup mTrack; private ScrollView mScroller; private OnPopuItemClickListener mItemClickListener; private OnDismissListener mDismissListener; private List<PopuItem> PopuItems = new ArrayList<PopuItem>(); private boolean mDidAction; private int mChildPos; private int mInsertPos; private int mAnimStyle; private int mOrientation; private int rootWidth=0; public static final int HORIZONTAL = 0; public static final int VERTICAL = 1; public static final int ANIM_GROW_FROM_LEFT = 1; public static final int ANIM_GROW_FROM_RIGHT = 2; public static final int ANIM_GROW_FROM_CENTER = 3; public static final int ANIM_REFLECT = 4; public static final int ANIM_AUTO = 5; /** * Constructor for default vertical layout * * @param context Context */ public PopuJar(Context context) { this(context, VERTICAL); } /** * Constructor allowing orientation override * * @param context Context * @param orientation Layout orientation, can be vartical or horizontal */ public PopuJar(Context context, int orientation) { super(context); mOrientation = orientation; mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (mOrientation == HORIZONTAL) { setRootViewId(R.layout.popup_horizontal); } else { setRootViewId(R.layout.popup_vertical); } mAnimStyle = ANIM_AUTO; mChildPos = 0; } /** * Get action item at an index * * @param index Index of item (position from callback) * * @return Action Item at the position */ public PopuItem getPopuItem(int index) { return PopuItems.get(index); } /** * Set root view. * * @param id Layout resource id */ public void setRootViewId(int id) { mRootView = (ViewGroup) mInflater.inflate(id, null); mTrack = (ViewGroup) mRootView.findViewById(R.id.tracks); mArrowDown = (ImageView) mRootView.findViewById(R.id.arrow_down); mArrowUp = (ImageView) mRootView.findViewById(R.id.arrow_up); mScroller = (ScrollView) mRootView.findViewById(R.id.scroller); //This was previously defined on show() method, moved here to prevent force close that occured //when tapping fastly on a view to show quickaction dialog. //Thanx to zammbi (github.com/zammbi) mRootView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); setContentView(mRootView); } /** * Set animation style * * @param mAnimStyle animation style, default is set to ANIM_AUTO */ public void setAnimStyle(int mAnimStyle) { this.mAnimStyle = mAnimStyle; } /** * Set listener for action item clicked. * * @param listener Listener */ public void setOnPopuItemClickListener(OnPopuItemClickListener listener) { mItemClickListener = listener; } /** * Add action item * * @param action {@link PopuItem} */ public void addPopuItem(PopuItem action) { PopuItems.add(action); String title = action.getTitle(); Drawable icon = action.getIcon(); View container; if (mOrientation == HORIZONTAL) { container = mInflater.inflate(R.layout.action_item_horizontal, null); } else { container = mInflater.inflate(R.layout.action_item_vertical, null); } ImageView img = (ImageView) container.findViewById(R.id.iv_icon); TextView text = (TextView) container.findViewById(R.id.tv_title); if (icon != null) { img.setImageDrawable(icon); } else { img.setVisibility(View.GONE); } if (title != null) { text.setText(title); } else { text.setVisibility(View.GONE); } final int pos = mChildPos; final int actionId = action.getActionId(); container.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mItemClickListener != null) { mItemClickListener.onItemClick(PopuJar.this, pos, actionId); } if (!getPopuItem(pos).isSticky()) { mDidAction = true; dismiss(); } } }); container.setFocusable(true); container.setClickable(true); if (mOrientation == HORIZONTAL && mChildPos != 0) { View separator = mInflater.inflate(R.layout.horiz_separator, null); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT); separator.setLayoutParams(params); separator.setPadding(5, 0, 5, 0); mTrack.addView(separator, mInsertPos); mInsertPos++; } mTrack.addView(container, mInsertPos); mChildPos++; mInsertPos++; } /** * Show quickaction popup. Popup is automatically positioned, on top or bottom of anchor view. * */ public void show (View anchor) { preShow(); int xPos, yPos, arrowPos; mDidAction = false; int[] location = new int[2]; anchor.getLocationOnScreen(location); Rect anchorRect = new Rect(location[0], location[1], location[0] + anchor.getWidth(), location[1] + anchor.getHeight()); //mRootView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); mRootView.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); int rootHeight = mRootView.getMeasuredHeight(); if (rootWidth == 0) { rootWidth = mRootView.getMeasuredWidth(); } int screenWidth = mWindowManager.getDefaultDisplay().getWidth(); int screenHeight = mWindowManager.getDefaultDisplay().getHeight(); //automatically get X coord of popup (top left) if ((anchorRect.left + rootWidth) > screenWidth) { xPos = anchorRect.left - (rootWidth-anchor.getWidth()); xPos = (xPos < 0) ? 0 : xPos; arrowPos = anchorRect.centerX()-xPos; } else { if (anchor.getWidth() > rootWidth) { xPos = anchorRect.centerX() - (rootWidth/2); } else { xPos = anchorRect.left; } arrowPos = anchorRect.centerX()-xPos; } int dyTop = anchorRect.top; int dyBottom = screenHeight - anchorRect.bottom; boolean onTop = (dyTop > dyBottom) ? true : false; if (onTop) { if (rootHeight > dyTop) { yPos = 15; LayoutParams l = mScroller.getLayoutParams(); l.height = dyTop - anchor.getHeight(); } else { yPos = anchorRect.top - rootHeight; } } else { yPos = anchorRect.bottom; if (rootHeight > dyBottom) { LayoutParams l = mScroller.getLayoutParams(); l.height = dyBottom; } } showArrow(((onTop) ? R.id.arrow_down : R.id.arrow_up), arrowPos); setAnimationStyle(screenWidth, anchorRect.centerX(), onTop); mWindow.showAtLocation(anchor, Gravity.NO_GRAVITY, xPos, yPos); } /** * Set animation style * * @param screenWidth screen width * @param requestedX distance from left edge * @param onTop flag to indicate where the popup should be displayed. Set TRUE if displayed on top of anchor view * and vice versa */ private void setAnimationStyle(int screenWidth, int requestedX, boolean onTop) { int arrowPos = requestedX - mArrowUp.getMeasuredWidth()/2; switch (mAnimStyle) { case ANIM_GROW_FROM_LEFT: mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left); break; case ANIM_GROW_FROM_RIGHT: mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right); break; case ANIM_GROW_FROM_CENTER: mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center); break; case ANIM_REFLECT: mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Reflect : R.style.Animations_PopDownMenu_Reflect); break; case ANIM_AUTO: if (arrowPos <= screenWidth/4) { mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left); } else if (arrowPos > screenWidth/4 && arrowPos < 3 * (screenWidth/4)) { mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center); } else { mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right); } break; } } /** * Show arrow * * @param whichArrow arrow type resource id * @param requestedX distance from left screen */ private void showArrow(int whichArrow, int requestedX) { final View showArrow = (whichArrow == R.id.arrow_up) ? mArrowUp : mArrowDown; final View hideArrow = (whichArrow == R.id.arrow_up) ? mArrowDown : mArrowUp; final int arrowWidth = mArrowUp.getMeasuredWidth(); showArrow.setVisibility(View.VISIBLE); ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams)showArrow.getLayoutParams(); param.leftMargin = requestedX - arrowWidth / 2; hideArrow.setVisibility(View.INVISIBLE); } /** * Set listener for window dismissed. This listener will only be fired if the quicakction dialog is dismissed * by clicking outside the dialog or clicking on sticky item. */ public void setOnDismissListener(PopuJar.OnDismissListener listener) { setOnDismissListener(this); mDismissListener = listener; } @Override public void onDismiss() { if (!mDidAction && mDismissListener != null) { mDismissListener.onDismiss(); } } /** * Listener for item click * */ public interface OnPopuItemClickListener { public abstract void onItemClick(PopuJar source, int pos, int actionId); } /** * Listener for window dismiss * */ public interface OnDismissListener { public abstract void onDismiss(); } } public class PopupWindows { protected Context mContext; protected PopupWindow mWindow; protected View mRootView; protected Drawable mBackground = null; protected WindowManager mWindowManager; /** * Constructor. * * @param context Context */ public PopupWindows(Context context) { mContext = context; mWindow = new PopupWindow(context); mWindow.setTouchInterceptor(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { mWindow.dismiss(); return true; } return false; } }); mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); } /** * On dismiss */ protected void onDismiss() { } /** * On show */ protected void onShow() { } /** * On pre show */ protected void preShow() { if (mRootView == null) throw new IllegalStateException("setContentView was not called with a view to display."); onShow(); if (mBackground == null) mWindow.setBackgroundDrawable(new BitmapDrawable()); else mWindow.setBackgroundDrawable(mBackground); mWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT); mWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT); mWindow.setTouchable(true); mWindow.setFocusable(true); mWindow.setOutsideTouchable(true); mWindow.setContentView(mRootView); } /** * Set background drawable. * * @param background Background drawable */ public void setBackgroundDrawable(Drawable background) { mBackground = background; } /** * Set content view. * * @param root Root view */ public void setContentView(View root) { mRootView = root; mWindow.setContentView(root); } /** * Set content view. * * @param layoutResID Resource id */ public void setContentView(int layoutResID) { LayoutInflater inflator = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); setContentView(inflator.inflate(layoutResID, null)); } /** * Set listener on window dismissed. * * @param listener */ public void setOnDismissListener(PopupWindow.OnDismissListener listener) { mWindow.setOnDismissListener(listener); } /** * Dismiss the popup window. */ public void dismiss() { mWindow.dismiss(); } } 显示popu: 参考: http://code.google.com/p/simple-quickactions/ 本文转自xyz_lmn51CTO博客,原文链接:http://blog.51cto.com/xyzlmn/817276,如需转载请自行联系原作者

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

Android Ap 开发 设计模式第四篇:工厂方法模式

Factory Method Pattern 模板模式的衍生品? 以Template Method Pattern 架构获取产生对象实例的工厂就是Factory Method Pattern。 工厂方法模式在父类规定对象的创建方法,但并没有深入到较具体的类名。所有具体的完整内容 都放在子类。根据这个原则,我们可以大致分成产生对象实例的大纲(框架)和实际生产对象实例的类两方面。 场景模拟 以一个工厂进厂打工为原型,工人们进厂须先登记信息,由所登记的信息进入创建工卡,工人们每天进厂必须使用工卡打卡,开始一天的劳动。以此为例,进行编程,设计UML图如下: 程序实现 抽象类Product定义抽象方法create ()表示创建用工card 信息和use () 表示用户使用card 抽象类Factory实现方法create 的抽象类,这里就是我们上文所说的为什么是模板方法模式衍生品。和定义抽象方法createProduct()、抽象方法registerProduct() 交由子类负责完成 。 类IDcard 继承自Product 实现方法use 和create 类IDCardFactory 继承 自Factory 实现方法createProduct、registerProduct Product 抽象类 public abstract class Product{ public abstract Stringcreate(); public abstract Stringuse(); } Factory 抽象类 public abstract class Factory{ public finalProductcreate(Stringowner){ Productp = createProduct(owner); registerProduct(p); return p; } protected abstract ProductcreateProduct(Stringowner); protected abstract void registerProduct(Productproduct); } IDCard 类 public class IDCardextendsProduct{ private Stringowner; public IDCard(Stringowner){ // TODOAuto-generatedconstructorstub this .owner = owner; } @Override public Stringuse(){ // TODOAuto-generatedmethodstub return " 使用 " + owner + " 的卡 " ; } public StringgetOwner(){ return owner; } @Override public Stringcreate(){ // TODOAuto-generatedmethodstub return " 建立 " + owner + " 的卡 " ; } } IDCardFactory 类 public class IDCardFactoryextendsFactory{ private Vector < String > owners = new Vector < String > (); @Override protected ProductcreateProduct(Stringowner){ // TODOAuto-generatedmethodstub return new IDCard(owner); } @Override protected void registerProduct(Productproduct){ // TODOAuto-generatedmethodstub owners.add(((IDCard)product).getOwner()); } public Vector < String > getOwners(){ return owners; } } 界面代码实现 FatoryMethodActivity: public class FatoryMethodActivityextendsActivityimplementsOnClickListener{ /* *Calledwhentheactivityisfirstcreated. */ @Override public void onCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); ((Button)findViewById(R.id.Button01)).setOnClickListener( this ); } @Override public void onClick(Viewv){ // TODOAuto-generatedmethodstub Factoryfactory = new IDCardFactory(); Productcard1 = factory.create( " terry " ); Productcard2 = factory.create( " paul " ); Productcard3 = factory.create( " jim " ); ((EditText)findViewById(R.id.EditText01)).setText(card1.create() + " , " + card1.use() + " \n " + card2.create() + " , " + card2.use() + " \n " + card3.create() + " , " + card3.use()); } } 最终实现效果: 代码下载: 工厂方法模式 本文转自 terry_龙 51CTO博客,原文链接:http://blog.51cto.com/terryblog/609318,如需转载请自行联系原作者

资源下载

更多资源
Nacos

Nacos

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

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

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部分的功能。

用户登录
用户注册