Android中View的滑动(一)

坐标系

安卓内部的坐标系分为两套坐标系,为安卓坐标系和视图坐标系。(似乎还有个全局坐标)

如图所示

视图坐标系(相对坐标)

视图坐标系的坐标是指以其parent视图的左上角为原点,x轴向右、y轴向下的一套坐标系。我们可以通过如下的一些方法获得该坐标系下的坐标点。

  • View中的方法:getTop、getBottom、getLeft、getRight。这些方法获得的都分别是这个view的左上角那一个点以及右下角那一个点的坐标的横纵坐标值;
  • MotionEvent提供的方法:getX、getY

安卓坐标系(绝对坐标)

该坐标系是指以屏幕上的左上角(实则就是整个window的左上角那个点)为原点,x轴向右、y轴向下的一套坐标系。有这样的方法可以获得该坐标:

  • MotionEvent提供的方法:getRawX、getRawY
  • 1
    2
    3
    4
    int[] location = new int[2] ;
    view.getLocationInWindow(location); //获取在当前窗口内的绝对坐标
    view.getLocationOnScreen(location);//获取在整个屏幕内的绝对坐标
    location [0]--->x坐标,location [1]--->y坐标

    要注意的是,这段代码需要在UI全部加载完毕之后调用才有效果,直接在onCreate中调用的话,所有返回的参数都会是0。

使用Scroller实现滑动

scroller实现滑动的原理还是通过view的ScrollTo以及ScrollerBy两个方法来实现。(实际上ScrollBy在原理上,也是通过包装ScrollTo之后得到的一个方法)

要注意的是scrollTo与scrollBy两个方法改变的是view内部的内容的“补偿值”,即getScrollX、getScrollY得到的两个值。这个滑动补偿值是等于view的左边界减去内容的左边界的值。

如图所示

weiter lesen

Messenger、Socket实现IPC

Messenger

Messenger是一种轻量级的IPC方案,其底层实现依旧是AIDL,不过Messenger只能处理较为简单但线程交流的情况。对于这一点,我们可以从它的构造方法也可以看出来。

1
2
3
public Messenger(IBinder target){
mTarget = IMessenger.Stub.asInterface(target);
}

服务端实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class AddLifeServiceMe extends Service {
public final static int REQUEST_FROM_CLIENT = 1;
public final static int ANSWER_FROM_SERVER = 2;
public static int liftLength = 0;
private static class MessageHandler extends Handler{
@Override
public void handleMessage(Message message){
switch (message.what){
case REQUEST_FROM_CLIENT:{
try {
liftLength++;
message.replyTo.send(Message.obtain(null, ANSWER_FROM_SERVER, liftLength, 0));
}catch (RemoteException re){
re.printStackTrace();
}
}
default:
super.handleMessage(message);
}
}
}
private final Messenger messenger = new Messenger(new MessageHandler());
@Nullable
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
}

weiter lesen

Android 制作一个评论框

需求介绍

我们经常在各种社交软件中经常能够看见评论框这一功能,这种评论框是用户在点击了某个“评论”按钮之后,会弹出这样一个评论框以及键盘,在用户输入完成之后或者点击任意其他位置之后就会消失。

微信朋友圈

分析一下之后,这种评论框有着这样的需求:

  1. 点击之后弹出这样一个带有EditText的布局;
  2. 弹出键盘;
  3. 点击回车可以完成输入;
  4. 弹出之后点击其他位置,布局消失,键盘收回。

经过一番思考之后,我认为使用自定义Dialog是实现这样的功能的较好方法,具体思路:

  1. Dialog自己可以实现弹出布局、点击其他位置时自动消失;
  2. Dialog通过设置theme以及WindowManager管理窗口外观;
  3. 键盘弹出、收回可以通过InputMethodManager实现;
  4. 点击回车完成输入可以通过OnEditorActionListener实现。

自定义Dialog

在我看来,实现一个Dialog和实现一个Fragment或者Acitivity差不多是一回事。都是自写一个继承Dialog的子类,在其中设置XML文件以及绑定各种控件方法就可以了。

设置theme

由于根据效果图来看,这个Dialog要实现水平方向充满屏幕、重力方向向下两个效果实现。所以我们需要在theme中像这样设置。

1
2
3
4
5
6
7
<style name="editDialogStyle" parent="android:style/Theme.Dialog">
<item name="android:windowBackground">@color/white10</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:scrollHorizontally">true</item>
</style>

windowContentOverlay设置的是ContentOverlay的背景

weiter lesen

Binder的学习

Binder是一个实现了IBinder接口的一个类。它是一种跨进程通信的方式,同时也是一种虚拟物理设备,同时也还是ServiceManager链接Manager和ManagerService的桥梁。当bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,可以通过这个对象来获取相应的服务或者数据。

AIDL

AIDL (Android Interface Definition Language) 是一种IDL,在Android中,我们可以通过AIDL由系统自动生成我们所需要的Binder类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// IAddLife.aidl
package com.project.tangyifeng.ipctest;
import com.project.tangyifeng.ipctest.IAddLifeListener;
// Declare any non-default types here with import statements
interface IAddLife {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
void addASecond();
void registerListener(IAddLifeListener listener);
void unregisterListener(IAddLifeListener listener);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// IAddLifeListener.aidl
package com.project.tangyifeng.ipctest;
// Declare any non-default types here with import statements
interface IAddLifeListener {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
void onLifeLengthened();
}

这两个文件可以在Android Studio中通过右键->Add->AIDL,就可以创建。在AIDL文件中,可以使用的数据类型包括下面几种:

  • 基本数据类型;
  • String 和 CharSequence;
  • List,只支持ArrayList,同时要求内部元素都能被支持;
  • Map,只支持HashMap,同时要求内部元素都能被支持;
  • Parcelable;
  • AIDL

注:如果AIDL中用到了自定义类,必须创建一个同名的AIDL文件;所有的在一个package内的AIDL还是必须互相import之后,才能正常使用。

weiter lesen

Android中的IPC机制

安卓的多进程机制:

  1. 对于安卓来说,每一个进程是在一个单独虚拟机中运行的。也就是说不能很简单的共享两个不同的虚拟机中的堆内存,必须要用Binder机制来进行管理。

  2. 多进程下会出现一下问题:

    • 静态成员和单例模式失效;
    • 线程同步机制失效;
    • SharedPreferences可靠性下降,本来在并发读写的时候可靠度就不是很高;
    • Application会被多次创建。
  3. 多进程的启动只需在四大组件中加入android:process属性即可。其中名字如果是以冒号:打头,表明是一个私有进程;如果包括了全部包名,就是公用进程,其他的应用可以通过ShareUID在同一个进程中进行访问,就好像是同一个应用的两个部分。关于ShareUserID的用法

安卓的多进程解决方案

详情见下表

表1

序列化

Serializable接口

只需要任意提供一个

1
private static final long serialVersionUID;

就可以自动序列化,这个是为了检查序列化版本是否相同。如果不自己指定一个的话,可能在类的结构发生改变之后使得不能反序列化回来。

weiter lesen

Tess4J学习

因为学院里的项目要求我们做一些OCR的工作,分工的时候分到了做文字识别这方面的活,于是就学习了一些tesseract、tess-two以及最主要的tess4J方面的东西。不得不说这个库对于中文真的是不怎么友好。。

Tess4J的导入

为了使用Tess4J,我们首先要去下载Tesseract。因为Tess4J实质上是对Tesseract在java中通过jni本地库之类的进行的封装。

  1. 下载Tesseract

    • Mac上可以直接通过

      1
      brew install tesseract

      就可以安装;

    • Windows上可以通过一个非官方的安装包安装下载链接
  2. Windows下需要配置环境变量;
  3. 下载Tess4J库Github地址
  4. 在IDE中配置好Library以及Modules。

Tess4J的使用

由于项目的识别要求比较低(大部分锅都交过了切图的大佬),所以也只是使用一小部分方法。大致就总结下列一些东西。

Tesseract的基本知识

  1. Tesseract的字典:在Tesseract的根目录下我们可以看到一个tessdata文件,里面有很多.traineddata文件,这些就是Tesseract的字典,这些文件是它识别各类文字的关键数据。同时也有一些常用词、生偏词的文件(感觉和中文没有什么关系。。),它们共同作用就可以进行识别。若想要识别其他语言,可以从github上面下载谷歌已经训练好的文件。下载链接
  2. 一些基本配置:在tessdata文件中我们也能看见一个config文件夹,打开里面可以看见几个文件。点开之后可以添加各种配置,比如说可以添加黑白名单(我也只用了白名单黑名单。。)。详情参见文档。
  3. 直接在命令行里面使用tesseract:
1
tesseract image.png image.txt -psm 6

原图:

原图

效果图

识别文件

weiter lesen


Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2018 Alex's Blog All Rights Reserved.

Yifeng Tang hält Urheberrechtsansprüche.