`

android 触屏反馈原理

 
阅读更多
android中触屏反馈原理


HOPE mt6516 android2.2 linux2.6.32

在用户对软按键或者某些ui操作的时候会反馈振动,达到让用户感知操作ok的效果。
在情景模式(Audio Profile)的选取之后,将会出现对特定情景模式设置的界面(Edit Profile),在这里面就可以设置是否启动振动器
和反馈功能。
情景模式对于的代码在:packages/apps/Settings/src/com/android/settings/audioprofile下,
其中文件:AudioProfileSettings.java是情景模式选择;Editprofile.java是情景模式编辑界面。

如果用户在界面上点击选中了反馈的功能,那么将会调用到函数:setHapticFeedbackEnabled()
@ frameworks/base/core/java/android/view/View.java
public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) {
        setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED);
    }
   
先来看看打电话界面的软键盘的触摸反馈功能的实现:
@packages/apps/Phone/src/com/android/phone
进入这个目录一眼就可以看到文件HapticFeedback.java,很显然,它就是实现振动反馈功能的,该文件代码比较简单:
该文件有一段较为详细的注释,说明了如何在代码中添加这个功能,使用它们的函数接口
/**
* Handles the haptic feedback: a light buzz happening when the user
* presses a soft key (UI button or capacitive key(电容虚拟按键)).
*
* The haptic feedback is controlled by:
* - a system resource for the pattern
*   The pattern used is tuned per device and stored in an internal
*   resource (config_virtualKeyVibePattern.)
*
* - a system setting HAPTIC_FEEDBACK_ENABLED.(这个就是情景模式中设置的反馈使能)
*   HAPTIC_FEEDBACK_ENABLED can be changed by the user using the
*   system Settings activity. It must be rechecked each time the
*   activity comes in the foreground (onResume).
*
* //////后面的代码可以看出,必须要这两个条件同时满足才可以调用振动器的接口。
*
* This class is not thread safe. It assumes it'll be called from the
* UI thead.
*
* Typical usage(典型用法):
* --------------
*   static private final boolean HAPTIC_ENABLED = true;
*   private HapticFeedback mHaptic = new HapticFeedback();
*
*   protected void onCreate(Bundle icicle) {
*     mHaptic.init((Context)this, HAPTIC_ENABLED);
*   }
*
*   protected void onResume() {
*     // Refresh the system setting.
*     mHaptic.checkSystemSetting();
*   }
*
*   public void foo() {
*     mHaptic.vibrate();
*   }
*
*/

public class HapticFeedback {
    private static final int VIBRATION_PATTERN_ID =
            com.android.internal.R.array.config_virtualKeyVibePattern;
    /** If no pattern was found, vibrate for a small amount of time. */
    private static final long DURATION = 10;  // millisec.
    /** Play the haptic pattern only once. */
    private static final int NO_REPEAT = -1;
   
    ...
     private Context mContext;
    private long[] mHapticPattern;
    private Vibrator mVibrator;

    private boolean mEnabled;
    private Settings.System mSystemSettings;
    private ContentResolver mContentResolver;
    private boolean mSettingEnabled;
   
    public void init(Context context, boolean enabled) {
        mEnabled = enabled;
        if (enabled) {
            mVibrator = new Vibrator();
            if (!loadHapticSystemPattern(context.getResources())) {
                mHapticPattern = new long[] {0, DURATION, 2 * DURATION, 3 * DURATION};
                // 设置一个默认的振动模式
            }
            mSystemSettings = new Settings.System();
            mContentResolver = context.getContentResolver();
        }
    }
   
    // Reload the system settings to check if the user enabled the haptic feedback.
    // called in onResume()
    public void checkSystemSetting() {
        if (!mEnabled) {
            return;
        }
        try {
            int val = mSystemSettings.getInt(mContentResolver, System.HAPTIC_FEEDBACK_ENABLED, 0);
            mSettingEnabled = val != 0; /////////////////
        } catch (Resources.NotFoundException nfe) {
            Log.e(TAG, "Could not retrieve system setting.", nfe);
            mSettingEnabled = false;
        }
    }
   
    public void vibrate() {
        if (!mEnabled || !mSettingEnabled) {
            return;  // 看得出,只有调用init时传入enable和用户设置使能反馈后才能调用振动器的接口
        }
        mVibrator.vibrate(mHapticPattern, NO_REPEAT);
    }
 
  /**
     * @return true If the system haptic pattern was found.
     * @加载振动模式
     */
    private boolean loadHapticSystemPattern(Resources r) {
        int[] pattern;

        mHapticPattern = null;
        try {
            pattern = r.getIntArray(VIBRATION_PATTERN_ID);
        } catch (Resources.NotFoundException nfe) {
            Log.e(TAG, "Vibrate pattern missing.", nfe);
            return false;
        }

        if (null == pattern || pattern.length == 0) {
            Log.e(TAG, "Haptic pattern is null or empty.");
            return false;
        }

        // int[] to long[] conversion.
        mHapticPattern = new long[pattern.length];
        for (int i = 0; i < pattern.length; i++) {
            mHapticPattern[i] = pattern[i];
        }
        return true;
    }
}

在打电话界面有两个文件中使用到这类API:EmergencyDialer.java (packages\apps\phone\src\com\android\phone)
             TwelveKeyDialer.java (packages\apps\contacts\src\com\android\contacts)
现在以拨号键盘为例:TwelveKeyDialer.java,搜索mHaptic.字符串即可找到。
mHaptic.init(this, r.getBoolean(R.bool.config_enable_dialer_key_vibration))
config_enable_dialer_key_vibration在下列文件中定义:
Config.xml (packages\apps\phone\res\values):    <bool name="config_enable_dialer_key_vibration">true</bool>

public void onClick(View view) {
        switch (view.getId()) {
            case R.id.one: {
                keyPressed(KeyEvent.KEYCODE_1);
                playTone(ToneGenerator.TONE_DTMF_1);
                mHaptic.vibrate();
                return;
            }
            ...
        }
    }
    
    protected void onResume() {
     ...
     // Retrieve the haptic feedback setting.
     mHaptic.checkSystemSetting();
     ...
    }

从上面的init函数调用和Config.xml可以看出,config_virtualKeyVibePattern模式并没有在phone的资源中定义,
直接使用的默认模式。
那么全局搜索了config_virtualKeyVibePattern这个字符串,发现只有在文件
Config.xml (frameworks\base\core\res\res\values)中有定义,而起还有另外4个类似的振动模式
<!-- Vibrator pattern for feedback about a long screen/key press -->
    <integer-array name="config_longPressVibePattern">
        <item>0</item>
        <item>1</item>
        <item>20</item>
        <item>21</item>
    </integer-array>

    <!-- Vibrator pattern for feedback about touching a virtual key -->
    <integer-array name="config_virtualKeyVibePattern">
        <item>0</item>
        <item>10</item>
        <item>20</item>
        <item>30</item>
    </integer-array>

    <!-- Vibrator pattern for a very short but reliable vibration for soft keyboard tap -->
    <integer-array name="config_keyboardTapVibePattern">
        <item>40</item>
    </integer-array>

    <!-- Vibrator pattern for feedback about booting with safe mode disabled -->
    <integer-array name="config_safeModeDisabledVibePattern">
        <item>0</item>
        <item>1</item>
        <item>20</item>
        <item>21</item>
    </integer-array>

    <!-- Vibrator pattern for feedback about booting with safe mode disabled -->
    <integer-array name="config_safeModeEnabledVibePattern">
        <item>0</item>
        <item>1</item>
        <item>20</item>
        <item>21</item>
        <item>500</item>
        <item>600</item>
    </integer-array>

那么上面类似的5中模式在哪里有使用呢?在刚刚的搜索结果中可以看到赫然出现一个文件:
PhoneWindowManager.java (frameworks\policies\base\phone\com\android\internal\policy\impl)
这个文件中的代码实现系统所有窗口的统一管理,那么显而易见大部分窗口振动都是在这里操作的。
public void init(Context context, IWindowManager windowManager,
            LocalPowerManager powerManager) {
      ...
       mVibrator = new Vibrator();
        mLongPressVibePattern = getLongIntArray(mContext.getResources(),
                com.android.internal.R.array.config_longPressVibePattern);
        mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(),
                com.android.internal.R.array.config_virtualKeyVibePattern);
        mKeyboardTapVibePattern = getLongIntArray(mContext.getResources(),
                com.android.internal.R.array.config_keyboardTapVibePattern);
        mSafeModeDisabledVibePattern = getLongIntArray(mContext.getResources(),
                com.android.internal.R.array.config_safeModeDisabledVibePattern);
        mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(),
                com.android.internal.R.array.config_safeModeEnabledVibePattern);
      // 取出振动模式数据,放在long []类型数组中。
     
     }

public boolean performHapticFeedbackLw(WindowState win, int effectId,
            boolean always) {
        final boolean hapticsDisabled = Settings.System.getInt(mContext
                .getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED,
                0) == 0;  // 再次获取用户设置
        if (!always
                && (hapticsDisabled || mKeyguardMediator
                        .isShowingAndNotHidden())) {
            return false;  //
        }
        long[] pattern = null;
        switch (effectId) {  // effectId这个值是觉得采用哪种模式的,长按,还是按了软按键产生等等。
        case HapticFeedbackConstants.LONG_PRESS:
            pattern = mLongPressVibePattern;
            break;
        case HapticFeedbackConstants.VIRTUAL_KEY:
            pattern = mVirtualKeyVibePattern;
            break;
        case HapticFeedbackConstants.KEYBOARD_TAP:
            pattern = mKeyboardTapVibePattern;
            break;
        case HapticFeedbackConstants.SAFE_MODE_DISABLED:
            pattern = mSafeModeDisabledVibePattern;
            break;
        case HapticFeedbackConstants.SAFE_MODE_ENABLED:
            pattern = mSafeModeEnabledVibePattern;
            break;
        default:
            return false;
        }
        // 调用振动器接口开始振动
        if (pattern.length == 1) {
            // One-shot vibration
            mVibrator.vibrate(pattern[0]);
        } else {
            // Pattern vibration
            mVibrator.vibrate(pattern, -1);
        }
        return true;
    }
   
    public void keyFeedbackFromInput(KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_DOWN
                && (event.getFlags() & KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) {
                // 这里有对按键类型做判断看是否是虚拟的硬按键,就对于这虚拟的软按键。
            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY,
                    false);
        }
    }

到这里,基本上大致明白了振动反馈的原理,现在要引入一个实际面临的问题。

本来Virtual Key是只的触摸屏上划出一块区域来做几个按键的这类按键,这类按键在原始系统上就是可以进行振动反馈的,
不过呢,现在我们的系统上有2个触摸按键MENU和BACK,他们虽然也是在触摸屏上,不过他们是按照按键上报,而不是按触摸
坐标上报之后生成的虚拟keyevent,所以这样的话,上层就会将他们视为物理按键,但是他们确实是触摸型的。
所以为了让这类按键触摸之后也有振动反馈,所以就需要查找按键上报的流程,然后进行修改。

获取按键的类型flags: event.getFlags(), KeyEvent.java (frameworks\base\core\java\android\view)
想要知道这个flags是如何来的,那么就需要从kernel内核之上开始顺藤摸瓜将按键上报流程缕一下:

EventHub.cpp (frameworks\base\libs\ui)
这个文件中的函数EventHub::getEvent()会从内核中获取input子系统的event事件,其中也包括key事件。
bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
        int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
        int32_t* outValue, nsecs_t* outWhen)
{
  ...
  while(1) {
   ...
   pollres = poll(mFDs, mFDCount, -1);
  
   ...
   for(i = 1; i < mFDCount; i++) {
            if(mFDs[i].revents) {
               
                if(mFDs[i].revents & POLLIN) {
                    res = read(mFDs[i].fd, &iev, sizeof(iev));
                    if (res == sizeof(iev)) {
                      
                        *outDeviceId = mDevices[i]->id;
                        if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
                        *outType = iev.type;
                        *outScancode = iev.code;
                        if (iev.type == EV_KEY) {
                            err = mDevices[i]->layoutMap->map(iev.code, outKeycode, outFlags);
                            // 从*.kl文件中进行键值映射,也得到想要flags值。kernel键值映射到android键值。

       ...
                        } else {
                            *outKeycode = iev.code;
                        }
                        *outValue = iev.value;
                        *outWhen = s2ns(iev.time.tv_sec) + us2ns(iev.time.tv_usec);
                        return true;
                    }
                    ...
                    }
                }
            }
        }
  ...
  }
}

*.kl文件格式:
key 158   BACK
...
key 229   MENU
key 139   MENU
key 59    MENU
...
key 116   POWER             WAKE
...

其中第一列是key关键字,第二列是kernel的键值,第3列是android键值,第4列是flag
其中flags有以下几种,可以从文件:KeycodeLabels.h (frameworks\base\include\ui)中查看得到:
static const KeycodeLabel FLAGS[] = {
     { "WAKE", 0x00000001 },
     { "WAKE_DROPPED", 0x00000002 },
     { "SHIFT", 0x00000004 },
     { "CAPS_LOCK", 0x00000008 },
     { "ALT", 0x00000010 },
     { "ALT_GR", 0x00000020 },
     { "MENU", 0x00000040 },
     { "LAUNCHER", 0x00000080 },
     { NULL, 0 }
};

其中也可以看到MENU和BACK在android空间中对于的键值分别是:82和4.
static const KeycodeLabel KEYCODES[] = {
  ...
  { "BACK", 4 },
  ...
  { "MENU", 82 },
  ...
}

上面这些值都是KeyLayoutMap.cpp (frameworks\base\libs\ui)文件中函数
status_t KeyLayoutMap::load(const char* filename)在加载*.kl文件的时候根据文件和上面两个数组设置好了的,最后只需要用map()函数来获取这些值即可。

接下来按键值将会上传至JNI层:com_android_server_KeyInputQueue.cpp (frameworks\base\services\jni)
static jboolean  android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz, jobject event)
{
    gLock.lock();
    sp<EventHub> hub = gHub;
    if (hub == NULL) {
        hub = new EventHub;
        gHub = hub;
    }
    gLock.unlock();

    int32_t deviceId;
    int32_t type;
    int32_t scancode, keycode;
    uint32_t flags;
    int32_t value;
    nsecs_t when;
    bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode, &flags, &value, &when);  // getEvent

    env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);
    env->SetIntField(event, gInputOffsets.mType, (jint)type);
    env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode);
    env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode);
    env->SetIntField(event, gInputOffsets.mFlags, (jint)flags);
    env->SetIntField(event, gInputOffsets.mValue, value);
    env->SetLongField(event, gInputOffsets.mWhen, (jlong)(nanoseconds_to_milliseconds(when)));
    // 将这些值传入java空间。

    return res;
}
最后在java代码中只需要调用jni接口readEvent即可。

KeyInputQueue.java (frameworks\base\services\java\com\android\server)文件中会创建一个线程来专门读取inputevent值

Thread mThread = new Thread("InputDeviceReader") {
  public void run() {
    ...
    RawInputEvent ev = new RawInputEvent();
         while (true) {
           try {
               InputDevice di;

               // block, doesn't release the monitor
               readEvent(ev);
              
               ...
              
               }
    }
   
    ...
    // Is it a key event?
         if (type == RawInputEvent.EV_KEY &&
             (classes&RawInputEvent.CLASS_KEYBOARD) != 0 &&
             (scancode < RawInputEvent.BTN_FIRST ||
              scancode > RawInputEvent.BTN_LAST)) {
                  boolean down;
                  if (ev.value != 0) {
                  down = true;
                  di.mKeyDownTime = curTime;
                  } else {
                     down = false;
                  }
                  int keycode = rotateKeyCodeLocked(ev.keycode);
                  addLocked(di, curTimeNano, ev.flags,
                            RawInputEvent.CLASS_KEYBOARD,
                            newKeyEvent(di, di.mKeyDownTime, curTime, down,
                                       keycode, 0, scancode,
                                       ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
                                       ? KeyEvent.FLAG_WOKE_HERE : 0));
         }
   
    ...
  
  }
}

generateVirtualKeyDown()根据上报的触摸点坐标等信息生成虚拟硬按键事件。
KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, true,
                    vk.lastKeycode, 0, vk.scancode,
                    KeyEvent.FLAG_VIRTUAL_HARD_KEY);
    mHapticFeedbackCallback.virtualKeyFeedback(event);
    addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
                    event);




newKeyEvent()生成一个KeyEvent实例,如下:
public static KeyEvent newKeyEvent(InputDevice device, long downTime,
            long eventTime, boolean down, int keycode, int repeatCount,
            int scancode, int flags) {
           
        return new KeyEvent(
                downTime, eventTime,
                down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
                keycode, repeatCount,
                device != null ? device.mMetaKeysState : 0,
                device != null ? device.id : -1, scancode,
                flags | KeyEvent.FLAG_FROM_SYSTEM);
    }
   
   
    ////***********************88   错误的修改  *******************************/
所以为了实现MENU和BACK按键能产生震动反馈,那么可以直接修改这个函数newKeyEvent(),如下:
public static KeyEvent newKeyEvent(InputDevice device, long downTime,
            long eventTime, boolean down, int keycode, int repeatCount,
            int scancode, int flags) {
+ int nflags = flags;
 
    +   if(keycode == 4 || keycode == 82)  // BACK and MENU
    +    nflags |= KeyEvent.FLAG_VIRTUAL_HARD_KEY;
        return new KeyEvent(
                downTime, eventTime,
                down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
                keycode, repeatCount,
                device != null ? device.mMetaKeysState : 0,
                device != null ? device.id : -1, scancode,
    +/-         nflags | KeyEvent.FLAG_FROM_SYSTEM);
    }
////***********************88   错误的修改  *******************************/


int keycode = rotateKeyCodeLocked(ev.keycode);
       /* Begin: lizhiguo, 2011-10-20, modifiled for BACK and MENU key HapticFeedback.*/
       if(1){
        int nflags = ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
                                              ? KeyEvent.FLAG_WOKE_HERE : 0;
        if(keycode == 4 || keycode == 82)   // BACK and MENU
         nflags |= KeyEvent.FLAG_VIRTUAL_HARD_KEY;

        KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, down,
                                             keycode, 0, scancode, nflags);

        if(keycode == 4 || keycode == 82)   // BACK and MENU
         mHapticFeedbackCallback.virtualKeyFeedback(event);
       
                             addLocked(di, curTimeNano, ev.flags,
                                     RawInputEvent.CLASS_KEYBOARD, event);
                            }
       else{
        addLocked(di, curTimeNano, ev.flags,
                               RawInputEvent.CLASS_KEYBOARD,
                               newKeyEvent(di, di.mKeyDownTime, curTime, down,
                                          keycode, 0, scancode,
                                          ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
                                          ? KeyEvent.FLAG_WOKE_HERE : 0));
       }
       /* End: lizhiguo, 2011-10-20 */


完!






源码列表:
1  KeyInputQueue.java (frameworks\base\services\java\com\android\server)
2  RawInputEvent.java (frameworks\base\core\java\android\view)
3  KeyEvent.java (frameworks\base\core\java\android\view)
4  KeyInputQueue.java (frameworks\base\services\java\com\android\server):2
5  WindowManagerPolicy.java (frameworks\base\core\java\android\view)
6  com_android_server_KeyInputQueue.cpp (frameworks\base\services\jni)
7  EventHub.cpp (frameworks\base\libs\ui)
8  EventHub.cpp (frameworks\base\libs\ui):2
9  KeyLayoutMap.cpp (frameworks\base\libs\ui)
0  KeycodeLabels.h (frameworks\base\include\ui)
A  TwelveKeyDialer.java (packages\apps\contacts\src\com\android\contacts)
B  PhoneWindowManager.java (frameworks\policies\base\phone\com\android\internal\policy\impl)
C  KeyEvent.java (frameworks\base\awt\java\awt\event)
D  HapticFeedbackConstants.java (frameworks\base\core\java\android\view)
E  PasswordUnlockScreen.java (frameworks\policies\base\phone\com\android\internal\policy\impl)
F  LockPatternView.java (frameworks\base\core\java\com\android\internal\widget)
G  HapticFeedback.java (packages\apps\phone\src\com\android\phone)
H  Donottranslate_config.xml (packages\apps\contacts\res\values)
I  EmergencyDialer.java (packages\apps\phone\src\com\android\phone)
J  Config.xml (frameworks\base\core\res\res\values)
K  Vibrator.java (frameworks\base\core\java\android\os)
L  View.java (frameworks\base\core\java\android\view)
M  Settings.java (frameworks\base\core\java\android\provider)
N  ContentResolver.java (frameworks\base\core\java\android\content)
O  System.java (dalvik\libcore\luni-kernel\src\main\java\java\lang)
P  Editprofile.java (packages\apps\settings\src\com\android\settings\audioprofile)
Q  CheckBoxPreference.java (frameworks\base\core\java\android\preference)
R  AudioProfileImpl.java (frameworks\mtk\extensions\media\audio\java\com\mediatek\audioprofile)
S  ProfileState.java (frameworks\mtk\extensions\media\audio\java\com\mediatek\audioprofile)
T  AudioProfileSettings.java (packages\apps\settings\src\com\android\settings\audioprofile)
U  Config.xml (packages\apps\phone\res\values)
V  TextKeyListenerTest.java (cts\tests\tests\text\src\android\text\method\cts)
W  WindowManagerService.java (frameworks\base\services\java\com\android\server)
X  KeyEventTest.java (cts\tests\tests\view\src\android\view\cts)
Y  KeyLayoutMap.h (frameworks\base\libs\ui)
Z  User_comments_for_4_to_5.xml (frameworks\base\docs\html\sdk\api_diff\5)
   missingSinces.txt (frameworks\base\docs\html\sdk\api_diff\5)
   5.xml (frameworks\base\api)
   MidWindowManager.java (frameworks\policies\base\mid\com\android\internal\policy\impl)
   EventHub.h (frameworks\base\include\ui)
   Evdev.c (kernel\drivers\input)
   Input.h (kernel\include\linux)
   Input.c (kernel\drivers\input)
   Preference.java (frameworks\base\core\java\android\preference)
分享到:
评论

相关推荐

    Android 触屏手势识别GestureTest-IT计算机-毕业设计.zip

    通过分析和学习这个GestureTest项目,开发者不仅可以掌握Android手势识别的基本原理和实现,还可以了解到如何将这些技术融入到实际应用中,提升用户的交互体验。对于Android初学者和毕业设计的参与者来说,这是一个...

    Android游戏源码支持触屏和按键的推箱子

    【Android游戏源码支持触屏和按键的推箱子】是一个基于Android平台的开源项目,它展示了如何在Android设备上实现一款经典...通过研究这个项目,开发者不仅可以提升Android编程技能,还能深入了解游戏开发的原理和实践。

    android触摸生成气泡

    首先,我们需要理解Android触摸事件的工作原理。在Android中,触摸事件通过MotionEvent类进行处理。当用户触摸屏幕时,系统会发送ACTION_DOWN事件,手指移动时会发送ACTION_MOVE事件,手指离开屏幕时则发送ACTION_UP...

    android桌面拖拽效果

    本文将深入探讨Android桌面拖拽效果的实现原理、关键技术和优化方法。 首先,我们需要理解Android桌面的基本架构。Android桌面,也被称为Launcher,是系统提供给用户启动应用、管理屏幕快捷方式和小部件的主要界面...

    Android9方格密码锁

    4. **视觉反馈**:提供解锁成功的动画效果,提升用户体验。 总之,Android 9方格密码锁是Android安全体系中的重要组成部分,通过合理的设计和实现,可以为用户提供便捷且安全的设备解锁体验。对于开发者来说,理解...

    Android手机交互特性

    在反馈方面,Android提供了较为丰富的反馈机制,如震动反馈、声音反馈以及视觉反馈等。这些反馈机制可以帮助用户更好地理解当前的操作状态,提高用户对应用的信任感。 **评分:** 80/100 ##### 3. 表意(Affordance...

    智能手机触屏滑动

    首先,触屏滑动的基本原理是通过电容式触摸屏来实现。电容式触摸屏由多层透明材料组成,包括导电层和绝缘层。当手指接触屏幕时,人体的电容会与屏幕的电容形成耦合,改变屏幕局部的电场分布。这一变化会被传感器检测...

    移动端触屏滑动导航菜单

    本篇文章将详细探讨移动端触屏滑动导航菜单的设计原理、实现方式以及优化策略。 一、设计原理 1. 滑动菜单的出现:滑动导航菜单通常隐藏在屏幕边缘,当用户触摸并滑动屏幕时,菜单会以动画效果滑出,展示更多的...

    android 开发之虚拟摇杆

    本篇文章将深入探讨Android虚拟摇杆的开发技术,包括原理、实现方法以及应用场景。 1. **虚拟摇杆的基本原理** - 虚拟摇杆主要由两个部分组成:一个可移动的“摇杆”图像和一个固定的基础背景。当用户触摸屏幕并...

    安卓Android源码——连连看.zip

    本文将深入探讨“连连看”这款游戏在Android平台上的实现原理,通过源码解析,帮助开发者理解Android应用开发的核心技术。 一、Android应用开发基础 1. **Activity与Layout** - Android应用的基础单元是Activity...

    p1_lte_sendEvent触屏事件记录

    【标题】"p1_lte_sendEvent触屏事件记录"主要涉及的是移动设备,特别是智能手机和平板电脑中,关于...通过研究这个功能,开发者可以提升对Android系统底层工作原理的理解,从而更好地优化应用程序的性能和用户体验。

    Focaltech(敦泰)触屏通用MTK驱动

    4. **响应反馈**:主处理器根据接收到的信息执行相应的操作,如屏幕触控事件的响应,然后将反馈信息传回触控驱动,最终完成用户的操作指令。 在安装【Focaltech(敦泰)触屏通用MTK驱动】时,用户需要注意以下几点...

    Android应用源码之mouseovertest1.zip

    通过分析和学习`mouseovertest`这个项目,开发者可以深入理解Android中鼠标悬停事件的工作原理,并将其应用到自己的应用中,提高应用的交互性和易用性。无论是为非触屏设备提供支持,还是为用户提供更丰富的触控体验...

    仿QQ微信手机端触屏滑动效果

    一、滑动效果基础原理 滑动效果主要依赖于触摸事件处理,包括`touchstart`、`touchmove`和`touchend`等。当用户在屏幕上触摸并移动手指时,这些事件会被触发,开发者可以通过监听这些事件来获取手指移动的距离和...

    Android应用源码之九宫格滑动解锁例子.zip

    首先,我们要理解九宫格解锁的基本原理。它由9个可点击的单元格组成一个3x3的矩阵,每个单元格代表不同的数字或图标。用户需要按照特定的顺序滑动这些单元格来完成解锁。这种解锁方式结合了触屏操作的便捷性和一定的...

    android游戏 雷电(源码+说明文档)

    本文将从源码分析和说明文档两方面,揭示这款游戏的制作原理和技术要点。 一、触控操作与游戏逻辑 "雷电"游戏的核心玩法是玩家通过触屏控制飞机移动,躲避敌机的子弹并反击。Android系统提供了丰富的触摸事件API,...

    电信设备-精密加工触屏可视化操作管理方法、移动终端和介质.zip

    这包括了图标、滑块、按钮等元素的设计,以及触控反馈、手势识别等技术。良好的可视化操作设计可以提升用户体验,简化复杂操作,使得电信设备更易于使用。 3. 操作管理系统:电信设备的操作管理系统是其软件层面的...

    适用于Android的轻手势解锁视图示例 - Java - 下载.zip

    6. **用户交互反馈**:为了提供良好的用户体验,手势解锁视图需要有视觉反馈,例如点亮用户触摸的格子、显示手势路径以及解锁成功或失败的提示。 7. **事件监听和处理**:在Java中,事件监听通常通过重写`...

    智力火柴游戏源码

    本篇文章将深入探讨“智力火柴游戏源码”,分析其设计原理,并结合Android游戏开发基础,为想要踏入移动游戏开发领域的朋友们提供宝贵的实践指导。 首先,我们要理解游戏的核心机制——算法。在这款游戏中,玩家...

    安卓平台输入法开发解析

    ### 安卓平台输入法开发解析 #### 一、安卓输入法框架概览 自Android 1.5版本以来,谷歌引入了输入法框架(Input Method Framework...理解并掌握这套框架的原理和机制,对于深入挖掘Android平台的输入潜力至关重要。

Global site tag (gtag.js) - Google Analytics