0%

UIImageView并不像UIButton一样,点点鼠标就可以关联点击事件,也不像Android里有onClickListener,这里需要借助于UITapGestureRecognizer类。从类名上就可以看出,这个类就是用于处理tap(单击)事件的。 bbc和voaspecial是UIImageView对象

    [bbc setUserInteractionEnabled:YES];
    [voaspecial setUserInteractionEnabled:YES];
    [bbc addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickCategory:)]];
    [voaspecial addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickCategory:)]];

经测试,多个UIImageView不能共用一个UITapGestureRecognizer对象,之前调用的会没效果。 根据点击的view判断来自谁的点击。

-(void)clickCategory:(UITapGestureRecognizer *)gestureRecognizer
{
    NSLog(@"click");
    NSLog(@"%hhd",[gestureRecognizer isMemberOfClass:[UITapGestureRecognizer class]]);
    
    UIView *viewClicked=[gestureRecognizer view];
    if (viewClicked==bbc) {
        NSLog(@"bbc");
    }else if(viewClicked==voaspecial)
    {
        NSLog(@"voaspecial");
    }
  
}

原理,在TextView的onTouch事件里,取到点击的座标,再根据y座标,找出第几行,再根据行号,找出该行显示的字符串,然后根据x座标,计算点击处的字符。如果处理中文,找到即可,找英文单词的话,在该字符前后查找,看其是否属于同一个单词。 根据x座标行内查找这里,应该有更快的算法,因为我用的的最笨的方法,希望得到高人指点。

textView.setOnTouchListener(new OnTouchListener() {
            
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO 自动生成的方法存根
                switch(event.getAction())
                {
                case MotionEvent.ACTION_DOWN:
                    float x=event.getX();
                    float y=event.getY();
                    //因为行设置行间距后,文本在顶部,空白在底部,加上一半的行间距,可以实现与文本垂直居中一样的效果
                    y=y+textView.getLineSpacingExtra()/2-textView.getPaddingTop();
                    //在顶部padding空白处点击
                    if(y<0)
                        return false;
                    int singleLineHeight=textView.getLineHeight();
                    StaticLayout layout=(StaticLayout)textView.getLayout();
                
                    int lineNumber=Math.round(y/singleLineHeight)-1;
                    if(lineNumber<0)
                        lineNumber=0;
                    if(lineNumber>textView.getLineCount()-1)
                        lineNumber-=1;
                    int start=layout.getLineStart(lineNumber);
                    int end=layout.getLineEnd(lineNumber);
                    
                    String str=textView.getText().toString().substring(start, end);
                 	Paint paint=new Paint();
                	paint.setTextSize(textView.getTextSize());//设置字符大小
                	//单字节占宽度
                	int sigleByteWidth=(int)paint.measureText("1", 0, 1);
                    
                	//减掉padding
                	float realX=x-textView.getPaddingLeft();
                	//在左侧padding空白处点击
                	if(realX<0)
                	{
                		return false;
                	}
                	//字符串可能的最大长度
                	//这里应该有更好更快的算法
                	int maxLength=(int)Math.floor(realX/sigleByteWidth);
                	//一般不会有字符显示超过两个1的宽度
                	int miniLenth=maxLength/2;
                	int strLength=str.length();
                	for(int i=strLength;i>=miniLenth;i--)
                	{
                		//字符串显示的宽度
                		float displayWidth=paint.measureText(str, 0, i);
                		if(Math.abs(displayWidth-realX)90&&clickChar<97)||clickChar>122)
                			{
                				return false;
                			}
                			//取单词,这段只针对英文,中文需要海量词库,太复杂了,前后看是不是空格或符号
                			StringBuilder sb=new StringBuilder();
                			sb.append(str.substring(i-1,i));
                			//查找前后的字符是否是同一个单词
                			String strBefore=str.substring(0,i-1);
                			String strAfter=str.substring(i,str.length());
                			
                			String strBeforeReverse=reverseStr(strBefore);
                			Pattern p1=Pattern.compile("(^[a-zA-Z]+)");
                			//正则
                			Matcher m1=p1.matcher(strBeforeReverse);
                			if(m1.find())
                			{
                				sb.insert(0, reverseStr(m1.group(1)));
                			}
                			
                			m1=p1.matcher(strAfter);
                			if(m1.find())
                			{
                				sb.append(m1.group(1));
                			}
                			System.out.println("点击单词"+sb.toString());
                			break;
                		}
                	}
                    break;
                }
                return false;
            }
        });



    /**
     * 反转字符串
     * @param s
     * @return
     */
    public String reverseStr(String s) {
        StringBuilder sb = new StringBuilder();
        for (int i = s.length() - 1; i >= 0; i--) {
            sb.append(s.charAt(i));
        }
        return sb.toString();
    }

Paint paint = new Paint();
paint.setTextSize(fontSize);
FontMetrics fm = paint.getFontMetrics();
int textHeight=(int) Math.ceil(fm.descent - fm.top) ;

如果要排除某些文件不提交,可以写规则到.gitignore文件中,但是.gitignore不能忽略自身,而我又不想把这个文件提交到server上,怎么办呢?可以编辑.git/info/exclude文件,语法与.gitignore一致。两个文件区别在于,exclude只用于设置本地需要忽略的文件,而.gitignore是公共需要排除的。

ctrl+command+left/right 编辑器中打开过的文件切换 command+click 在方法名或类名上操作,打开相应的头文件 option+click 在方法名或类名上操作,打开一个小窗口,提示该类或方法的信息。 command+/ 选中行或光标所在行注释 command+. 代码提示 command+r 编译运行 command+option+shift+? 打开帮助文档 command+option+2 在右侧工具面板显示Quick Help command+option+1 在右侧工具面板显示File Inspector(默认,与编辑内容相关) command+shift+2 打开Organizer窗口(Devices,Projects,Archives) command+1,2,3,4,5,6,7,8,右侧导航面板在Project Navigator,Symbol Navigator,Find Navigator,Issue Navigator,Test Navigator,Debug Navigator,Breakpoint Navigator,Log Navigator间切换 command+left/right 将光标移动到所在行的开始或结束,相当于windows里的Home和End的功能。好像home和end,pageup,pagedown在xcode中无效 command+backspace 将光标所在行中,光标前的内容删除。如果先command+right,再command+backspace,就是删除整行。 不定期更新…

默认情况下,command+click是在当前的tab中打开h头文件,这样要回到原来编辑的文件,就比较麻烦,如果可以像eclipse中一样,能开个新的tab,就很方便了。 解决方案: 第一种:command+t,复制一个当前tab,然后再command+click 第二种: 打开Perferences–Navigation,设置Double Click Navigation为Use Separate Tab,如果需要在新tab中打开头文件,可以command+double click

结果是: Integer.toString(i)>String.valueOf(i)>””+i 好吧,我是看到””+1这种奇葩写法才想确认一下哪种效率最高。

我的机器是mac mini,Debug时狂按F5,F6没反应,打开eclipse设置重新设置快捷键,发现可以输入ctrl+f5,但就是不能输入f5,应该是快捷键与系统冲突了。打开系统快捷键设置,果然,F5,F6被设成了调节亮度,但因为我的机器不是笔记本,不能调节外接显示器亮度,所以按了没反应,果断取消。

这应该是TextView的一个BUG,本来设置android:ellipsize=“end”以后,当字符串宽度超出TextView宽度,会在截断String,加上…,但是当字符串只超出1个字符时,最后一个字符被截断,却没有加…,网上搜索了好久也没找到适用的解决方案。最后,我们牛B的PM一句话解决,字符串结尾加空格!如果字符串占用宽度刚好等于TextView宽度,多一个空格,相当于只多一个字符,自动被截断,跟没加效果相同。如果字符串占用宽度比TextView的宽度,还要多一个字符,再加一个空格,相当于多了两个字符,就会截断加上…

翻译自:http://developer.android.com/training/articles/perf-tips.html 一、避免创建不必要的对象 1、如果一个方法返回String,而这个返回值要附加到StringBuffer,那么,应该直接append(方法),不要再有中间临时变量。 2、当从一组输入数据中提取字符串时,尝试使用子串,不要创建一个拷贝。你会创建一个新的String,但是会与原数据共享char[]。需要权衡的是,所有原始输入数据都在在内存中,如果你只使用原数据的一小部分,会浪费一些内存。 更激进彻底的方法是,把多维数组转成多个一维数组。 1、int数组比Integer数组更好,两个平行数组int[]比一个二维数组int[][]更有效,其他基本类型也一样 2、如果要实现一个容器类来保存Foo、Bar,记住:两个一维数组Foo[]和Bar[]比容器数组更高效。(如果是开发提供给别人使用的API,还是使用类封装一下比较好,更容易理解。但自己用的话,你应该尝试更高效的写法) 一般而言,尽可能避免创建短期临时变量。越少的对象创建,意味着GC的频率越低,对提升用户体验有直接效果。 二、使用static 如果不需要访问实例变量,应该把方法声明成static,调用速度会提高15%-20%。这也是一个很好的实践,因为你可以从方法声明辨认出该方法不能改变对象状态。 三、常量使用static final 看下面的声明:

static int intVal = 42;
static String strVal = "Hello, world!";

编译器生成一个叫的类初始化方法,当类第一次加载时执行。该方法保存42到intVal,并且从class文件的string常量表提取一个引用给strVal。当这些值被引用的时候,通过字段查找来找到这些变量。 可以通过加入final来改善:

static final int intVal = 42;
static final String strVal = "Hello, world!";

该类不再需要方法,因为常量进入dex文件的静态字段初始化器中,引用intVal的代码将会直接使用42,而访问strVal会使用相对高效的”string constant” 指令替代字段查找。这条优化建议只适用于原始数据类型和String,非所有引用类型。但尽可能地用static final声明常量是一条很好的实践。 尼玛,上面是直接翻的,自己感觉都看不懂,我的理解是,编译生成的class文件,所有引用intVal的地方直接换成了42,而字符串,会有一个常量池,不知道对不对。 四、避免内部调用Getter/Setter 在像C++这样的Native(相对Java的虚拟机)语言中,通常做法是使用Getter(i = getCount())代替直接访问字段(i = mCount),这是一个极好的习惯,并且在其他面向对象语言中像C#,Java也经常这么用,因为编译器通常可以内联访问,并且如果你需要限制访问或Debug字段访问,可以随时在setter/getter中添加代码。 然而,在Android这样做不是个主意。Virtual method调用是非常昂贵的,远超字段查找。跟随通用的面对对象编程实践,使用Getter/Setter是合理的,但在一个类中,你应该直接访问字段。(根据wikipedia,Virtual method指的是可以被子类覆盖的方法,http://en.wikipedia.org/wiki/Virtual_function) 没有JIT,直接访问字段比调用Getter快3倍,有JIT(字段访问与局部变量访问开销一样),直接访问字段比调用Getter快7倍。 如果你用ProGuard,你可以鱼与熊掌兼得,因为ProGuard会内联存取器(setter/getter). 五、使用增强的for循环语法。 增强的for循环(for-each)可以用于实现Iterable接口的集合和数组。在集合中,迭代器分配给接口调用hasNext() 和next()方法。使用ArrayList,hand-written counted loop大概要快3倍(不管有没有JIT),但是其他集合类使用for-each循环和显示使用迭代器相当。 注:hand-written counted loop,我也不知道是啥,我猜应该是for(int i=0;i static class Foo { int mSplat; } Foo[] mArray = ... public void zero() { int sum = 0; for (int i = 0; i < mArray.length; ++i) { sum += mArray[i].mSplat; } } public void one() { int sum = 0; Foo[] localArray = mArray; int len = localArray.length; for (int i = 0; i < len; ++i) { sum += localArray[i].mSplat; } } public void two() { int sum = 0; for (Foo a : mArray) { sum += a.mSplat; } } zero()最慢,因为JIT还不能优化在循环中每次迭代获取数组长度的开销。 one()较快,它把所有变量放到了局部变量中,避免了查找,数组长度只需要读一次。 two()在没有JIT的设备中最快。在有JIT的设备中,与one()相同。它使用了在Java 1.5(5.0)中介绍的增强的for循环。 所以,除了ArrayList外,能用for each的都用for each. 六、使用package代替内部private类访问内部private字段方法。 水平有限,这段不翻了,从举的例子来看大部分人也不会这么用,最终原因参考以上第四条,因为内部私有类访问内部私有字段方法会转换成访问Setter/Getter,建议把private换成package(默认) 七、避免使用Float 一般来说,在Android设备上,浮点数要比整数慢2倍。 在速度上,float和double在现代的设备上没有什么区别,在空间上,double是float的两倍。在电脑上,假设空间不是问题,你应该使用double而不是float. 同样,即使是整数,一些处理器有硬件乘法而没有硬件除法。In such cases, integer division and modulus operations are performed in software—something to think about if you’re designing a hash table or doing lots of math.好吧,这句不会翻。 八、了解并使用库 这条偷懒。Google写的代码通常比你自己写的性能好,有现成的库就用现成的。System.arraycopy()在Nexus one上比手写循环快9倍。 九、小心使用Native方法 使用NDK写Native代码不一定比用Java写更高效。首先,JNI转换有消耗,并且JIT不能优化。如果你分配了Native资源(堆内存,文件或其他),回收资源更麻烦。你还需要为每个需要支持的构架编译so文件(而不是依靠JIT),你甚至不得不为相同的构架编译多个不同的版本,为G1 ARM处理器编译的Native代码,在Nexus one的Arm处理器上不能充分利用.为Nexus one的ARM处理器编译的native代码不能在G1上工作。当你想把现有的Native代码库移植到Android上是,Native代码是很有用的,但不能为了加速你的应用而把Java换成Native. 十、性能误区 在没有JIT的设备上,调用一个准确类型变量的方法比调用该类型实现接口的方法稍微高效一些(向上转型要低效一些).举例来说,声明HashMap map比声明Map map更高效,即使两个都是HashMap.大概有6%的性能损失,用了JIT,基本没区别。 在没有JIT的设备中,缓存字段访问比重复访问字段要快20%,有JIT,字段访问与局部变量访问开销一样,所以这不值得你去优化,除非你觉得这使代码可读性更高。(这条对static,final,static final同样适用) 十一、测量 在你开始优化之前,确保你有问题需要解决(没问题优化个毛)。确保你能精确的测量你已存在的性能,否则你不能衡量修改后的好处。