打造酷炫AndroidStudio插件剖析Word格式文档下载.docx
《打造酷炫AndroidStudio插件剖析Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《打造酷炫AndroidStudio插件剖析Word格式文档下载.docx(12页珍藏版)》请在冰豆网上搜索。
只需实现PersistentStateComponent接口即可。
用户未点击Action时,能自动注册DocumentListener。
这主要是考虑到,用户开启了插件,下一次打开AndroidStudio时无需点击Aciton,直接输入时就能自动注册监听Document变化。
由于注册DocumentListener需要Editor对象,而想要取得Editor对象只有两种方式:
通过AnActionEvent对象的getData函数;
另一种是通过DataContext对象,使用
PlatformDataKeys.EDITOR.getData(dataContext)方法。
显然第一种方法只能在AnAction类的actionPerformed和update方法中才能取得。
因此只能考虑用第二种方法,而在前面文章中介绍过,监听键盘字符输入时,可以取得DataContext对象。
即重写TypedActionHandler接口的execute函数,execute参数中传递了DataContext对象。
可以看到,以上用到的知识都是前面3篇文章中介绍过的内容,并不复杂。
只有第6条没有介绍,本文中会学习本地持久化数据。
2.插件状态本地持久化
先看看如何实现本地持久化。
首先定义一个全局共享变量类GlobalVar,使之实现PersistentStateComponent接口。
先来个视觉上的认识,直接看代码。
/**
*配置文件
*Createdbyhuachaoon2016/12/27.
*/
@State(
name="
amazing-mode"
storages={
@Storage(
id="
file="
$APP_CONFIG$/amazing-mode_setting.xml"
)
}
)
publicclassGlobalVarimplementsPersistentStateComponent<
GlobalVar.State>
{
publicstaticfinalclassState{
publicbooleanIS_ENABLE;
publicbooleanIS_RANDOM;
@Nullable
@Override
publicStategetState(){
returnthis.state;
publicvoidloadState(Statestate){
this.state=state;
publicStatestate=newState();
publicGlobalVar(){
state.IS_ENABLE=false;
state.IS_RANDOM=false;
publicstaticGlobalVargetInstance(){
returnServiceManager.getService(GlobalVar.class);
}
使用@State注解指定本地存储位置、id等。
具体实现基本可以参照这个模板写,就是重写loadState()和getState()两个函数。
另外需要注意一下getInstance()函数的写法。
基本模板就这样,没有什么特别的地方,依葫芦画瓢就行。
还有一点特别重要,一定要记得在plugin.xml中注册这个持久化类。
找到<
extensions>
标签,加入<
applicationService>
子标签,如下:
<
extensionsdefaultExtensionNs="
com.intellij"
>
<
!
--Addyourextensionshere-->
applicationService
serviceImplementation="
com.huachao.plugin.util.GlobalVar"
serviceInterface="
/>
/extensions>
这样写完以后,在获取数据的时候,直接如下:
privateGlobalVar.Statestate=GlobalVar.getInstance().state;
//state.IS_ENABLE
//state.IS_RANDOM
3.编写Action
主要包含2个Action:
EnableAction和RandomColorAction。
EnableAction用于设置插件的开启或关闭,RandomColorAction用于设置是否使用随机颜色。
由于二者功能类似,我们只看看EnableAction的实现:
publicclassEnableActionextendsAnAction{
privateGlobalVar.Statestate=GlobalVar.getInstance().state;
publicvoidupdate(AnActionEvente){
Projectproject=e.getData(PlatformDataKeys.PROJECT);
Editoreditor=e.getData(PlatformDataKeys.EDITOR);
if(editor==null||project==null){
e.getPresentation().setEnabled(false);
}else{
JComponentcomponent=editor.getContentComponent();
if(component==null){
e.getPresentation().setEnabled(true);
updateState(e.getPresentation());
publicvoidactionPerformed(AnActionEvente){
return;
if(component==null)
state.IS_ENABLE=!
state.IS_ENABLE;
//只要点击Enable项,就把缓存中所有的文本清理
CharPanel.getInstance(component).clearAllStr();
GlobalVar.registerDocumentListener(project,editor,state.IS_ENABLE);
privatevoidupdateState(Presentationpresentation){
if(state.IS_ENABLE){
presentation.setText("
Enable"
);
presentation.setIcon(AllIcons.General.InspectionsOK);
Disable"
presentation.setIcon(AllIcons.Actions.Cancel);
代码比较简单,跟前面几篇文章中写的很相似。
只需注意一下actionPerformed函数中调用了两个函数:
CharPanel.getInstance(component).clearAllStr();
GlobalVar.registerDocumentListener(project,editor,state.IS_ENABLE);
CharPanel对象中的clearAllStr()函数后面介绍,只需知道它是将缓存中的所有动画对象清除。
GlobalVar对象中的registerDocumentListener()函数是添加DocumentListener监听器。
实现本文效果的中枢是DocumentListener监听器,是通过监听文本内容发生变化来获取实现字符动画效果的数据。
因此应应可能早地将DocumentListener监听器加入,而DocumentListener监听器加入的时刻包括:
用户点击Action、用户敲入字符。
也就是说,多个地方都存在添加DocumentListener监听器的可能。
因此把这个函数抽出来,加入到GlobalVar中,具体实现如下:
privatestaticAmazingDocumentListeneramazingDocumentListener=null;
publicstaticvoidregisterDocumentListener(Projectproject,Editoreditor,booleanisFromEnableAction){
if(!
hasAddListener||isFromEnableAction){
hasAddListener=rue;
if(amazingDocumentListener==null){
amazingDocumentListener=newAmazingDocumentListener(project);
Documentdocument=editor.getDocument();
document.addDocumentListener(amazingDocumentListener);
Threadthread=newThread(CharPanel.getInstance(component));
thread.start();
可以看到,一旦DocumentListener监听器被加入,就会开启一个线程,这个线程是一直执行,实现动画效果。
DocumentListener监听器只需加入一次即可。
4.实现动画
前面多次使用到了CharPanel对象,CharPanel对象就是用于实现动画效果。
先源码:
packagecom.huachao.plugin.util;
importcom.huachao.plugin.Entity.CharObj;
importjavax.swing.*;
importjava.awt.*;
importjava.util.*;
importjava.util.List;
publicclassCharPanelimplementsRunnable{
privateJComponentmComponent;
privatePointmCurPosition;
privateSet<
CharObj>
charSet=newHashSet<
();
privateList<
bufferList=newArrayList<
publicvoidsetComponent(JComponentcomponent){
mComponent=component;
publicvoidrun(){
while(state.IS_ENABLE){
if(GlobalVar.font!
=null){
synchronized(bufferList){
charSet.addAll(bufferList);
bufferList.clear();
draw();
intminFontSize=GlobalVar.font.getSize();
//修改各个Label的属性,使之能以动画形式出现和消失
Iterator<
it=charSet.iterator();
while(it.hasNext()){
CharObjobj=it.next();
if(obj.isAdd()){//如果是添加到文本框
if(obj.getSize()<
=minFontSize){//当字体大小到达最小后,使之消失
mComponent.remove(obj.getLabel());
it.remove();
}else{//否则,继续减小
intsize=obj.getSize()-6<
minFontSize?
minFontSize:
(obj.getSize()-6);
obj.setSize(size);
}else{//如果是从文本框中删除
Pointp=obj.getPosition();
if(p.y<
=0||obj.getSize()<
=0){//如果到达最底下,则清理
p.y=p.y-10;
intsize=obj.getSize()-1<
0?
0:
(obj.getSize()-1);
try{
if(charSet.isEmpty()){
synchronized(charSet){
charSet.wait();
Thread.currentThread().sleep(50);
}catch(InterruptedExceptione){
e.printStackTrace();
//绘制文本,本质上只是修改各个文本的位置和字体大小
privatevoiddraw(){
if(mComponent==null)
for(CharObjobj:
charSet){
JLabellabel=obj.getLabel();
Fontfont=newFont(GlobalVar.font.getName(),GlobalVar.font.getStyle(),obj.getSize());
label.setFont(font);
FontMetricsmetrics=label.getFontMetrics(label.getFont());
inttextH=metrics.getHeight();
//字符串的高,只和字体有关
inttextW=metrics.stringWidth(label.getText());
//字符串的宽
label.setBounds(obj.getPosition().x,obj.getPosition().y-(textH-GlobalVar.minTextHeight),textW,textH);
mComponent.invalidate();
publicvoidclearAllStr(){
charSet.clear();
setIt=charSet.iterator();
while(setIt.hasNext()){
CharObjobj=setIt.next();
bufferIt=bufferList.iterator();
while(bufferIt.hasNext()){
CharObjobj=bufferIt.next();
}
//单例模式,静态内部类
privatestaticclassSingletonHolder{
//静态初始化器,由JVM来保证线程安全
privatestaticCharPanelinstance=newCharPanel();
//返回单例对象
publicstaticCharPanelgetInstance(JComponentcomponent){
if(nent!
SingletonHolder.instance.mComponent=component;
returnSingletonHolder.instance;
//由光标监听器回调,由此可动态获取当前光标位置
publicvoidsetPosition(Pointposition){
this.mCurPosition=position;
/**
*将字符串添加到列表中。
*
*@isAdd如果为true表示十新增字符串,否则为被删除字符串
*@str字符串
publicvoidaddStrToList(Stringstr,booleanisAdd){
if(mComponent!
=null&
&
mCurPosition!
CharObjcharObj=newCharObj(mCurPosition.y);
JLabellabel=newJLabel(str);
charObj.setStr(str);
charObj.setAdd(isAdd);
charObj.setLabel(label);
if(isAdd)
charObj.setSize(60);
else
charObj.setSize(GlobalVar.font.getSize());
charObj.setPosition(mCurPosition);
if(state.IS_RANDOM){
label.setForeground(randomColor());
label.setForeground(GlobalVar.defaultForgroundColor);
bufferList.add(charObj);
charSet.notify();
mComponent.add(label);
//以下用于产生随机颜色
privatestaticfinalColor[]COLORS={Color.GREEN,Color.BLACK,Color.BLUE,Color.ORANGE,Color.YELLOW,Color.RED,Color.CYAN,Color.MAGENTA};
privateColorrandomColor(){
intmax=COLORS.length;
intindex=newRandom().nextInt(max);
returnCOLORS[index];
解释一下两个关键函数run()和draw()。
run()函数是开启新线程开始执行的函数,它的实现是一个循环,当插件开启时会一直循环运行。
CharPanel使用了2个集合来保持用户删除或者添加的字符串