jolfe的安卓之旅_04ImageButton.setOnFocusChangeListener

本文详细解析了Android应用中使用ImageButton时遇到焦点监听事件无法触发的问题,通过实验发现ImageButton的焦点属性需要手动调整才能触发焦点事件。文章还提供了测试代码,帮助开发者更好地理解和解决此类问题。

前两天imagebutton的焦点监听事件没办法触发,十分的郁闷,跟人感觉Google SDK这本书在这里的这个例子做的不好 容易让人迷惑,网上看了很多人,也只是抄了代码,没有具体说明原理性的东西,反正我是郁闷了两天,加上昨天刷机用了一天,所以今天回头重新理解了一下,现在将自己总体的理解写到这里,希望大家能互相学习。

具体的情况是ImageButton.setOnFocusChangeListener(new MyLitener());在设置后看不到触发的效果,我在对应的监听事件里加了Log也一直没有打印出来,所有就有点晕乎了,最后花了今天早上的时间,总算理解过来怎么回事了,好吧,又废话了,下面说明原因:

先把ImageButton的点击事件注释掉,完全觉得没必要,会影响你的判断,因为即使失去焦点还是会触发的。

我利用另一个button通过ImageButton.setFocusable((true or false);myImageButton.setFocusableInTouchMode(true or false);来控制ImageButton获取焦点的可行性,原因会在后面说明。

1、当我刚进应用,点击imagebutton的时候setOnFocusChangeListener()没有被触发(调试数据发现Focus为false),

2、即使设置了myImageButton.setFocusable(true);myImageButton.setFocusableInTouchMode(true);打印的结果依旧Focus仍然为false,但是当我再点击imagebutton时候可以触发一次MyLitener,(焦点监听事件被触发,imagebutton对应的内容被修改了。。。),

3、可是当我再点击一次button的时候,不用再点击imagebutton,imagebutton的对应内容直接被修改了。这下子我有点恍然大悟的感觉。

并且去查了myImageButton.setFocusable(true);myImageButton.setFocusableInTouchMode(true)这两个方法的作用,现总结完这些,下面会讲解一下

小总结:

ImageButton.setFocusable((true or false);myImageButton.setFocusableInTouchMode(true or false);都为true的时候代表的是,你对应设置的这个空间可以获取焦点了(而不是获取焦点,注意是  可以获取,不是已经获取)这意味着你必须点击ImageButton才能真正的改变Focus的值,也就是触发了一次焦点监听事件。

当imagebutton处于已经获取焦点的状态也就是Focus,再次修改ImageButton.setFocusable((true or false);myImageButton.setFocusableInTouchMode(true or false);的值为false的时候,会立刻触发焦点监听事件,这只是google的一种设计,你千万别问我这个是为什么,我只能说合乎情理,都不要焦点了还要再点击一次才能失去焦点有什么意义呢。

以上就是我对焦点监听事件的总结,本来以为很简单,却被晕倒里面,所以彻底的了解下,之后会贴出测试代码。

补充:如果直接在xml文件里面设置这两个属性为true,在打开应用的时候,会直接修改Focus为true,并触发一次监听事件,郁闷干嘛不在代码里面也直接做成直接修改焦点(再次提醒,代码里面设置了代表下次点击对应空间是可获取)

获取焦点的表现就是你点击的按钮的背景色一直都在不会消失。

好了 现在说明下上面要说的myImageButton.setFocusable(true);myImageButton.setFocusableInTouchMode(true)这两个方法的作用;

分三种情况(代码中测试)

1、setFocusable()   设置是否可以指向(不太理解这句话),总是这里修改了才能在你点击imagebutton的时候Focus的值才会改变,如果不设置,你懂的,焦点监听是不可能被触发的,因为Focus的不会改变。可以理解为预先设置下次点击之后要修改的Focus的值,等待点击之后修改为setFocusable所设置的值

2、setFocusableInTouchMode()  设置Focus改变的方式,如果设置为true,默认为手指点击时候改变。其他的没研究过,知道的给我讲讲,求讲解。


下面把代码贴出来

代码

package google.sdk.test_04_02;


import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;


public class MainActivity extends Activity {
private ImageButton myImageButton;
private Button myButton;
private TextView myTextView;


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


// 创建三个组件
myImageButton = (ImageButton) findViewById(R.id.myImageButton1);
myButton = (Button) findViewById(R.id.myButton1);
myTextView = (TextView) findViewById(R.id.myTextView1);


// 通过OnFocusChangeListener来响应ImageButton的onFocus事件
myImageButton.setOnFocusChangeListener(new MyOnFocusChangeListener());


// 通过onClickListener来响应ImageButton的onClick事件
// myImageButton.setOnClickListener(new OnClickListener() {
// public void onClick(View v) {
// if (myTextView.getText().toString().trim()
// .equals("图片按钮状态为: Got Click.iconfull")) {
// // 如果ImageButton状态为onClick则改变ImageButton的图片和说明
// myTextView.setText("图片按钮状态为: Got Click.iconempty");
// myImageButton.setImageResource(R.drawable.iconempty);
// } else {
// // 如果ImageButton状态为onClick则改变ImageButton的图片和说明
// myTextView.setText("图片按钮状态为: Got Click.iconfull");
// myImageButton.setImageResource(R.drawable.iconfull);
// }
//
// }
// });


// 通过onClickListener来响应Button的onClick事件
myButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {


// // 如果Button状态为onClick改变ImageButton图片
// myTextView.setText("图片按钮状态为:Lost Focus");
// myImageButton.setImageResource(R.drawable.iconempty);
if (myImageButton.hasFocus()) {
Log.i("myImageButton.hasFocus()", myImageButton.hasFocus()
+ "1");
myImageButton.setFocusableInTouchMode(false);
myImageButton.setFocusable(false);
// myTextView.setText("失去焦点");
Log.i("myImageButton.hasFocus()", myImageButton.hasFocus()
+ "2");
} else if (!myImageButton.hasFocus()) {
Log.i("myImageButton.hasFocus()", myImageButton.hasFocus()
+ "3");
myTextView.setText("获取了焦点");
myImageButton.setFocusable(true);
myImageButton.setFocusableInTouchMode(isChild());
Log.i("myImageButton.hasFocus()", myImageButton.hasFocus()
+ "4");
}
}
});
}


class MyOnFocusChangeListener implements OnFocusChangeListener {


@Override
public void onFocusChange(View v, boolean hasFocus) {

if (hasFocus == true) {
Log.i("myImageButton.hasFocus()", myImageButton.hasFocus() + "5");
// 更改状态说明
myTextView.setText("图片按钮状态为:Got Focus");
// 更改按钮背景图片
myImageButton.setImageResource(R.drawable.iconfull);
} else if (!hasFocus) {
Log.i("myImageButton.hasFocus()", myImageButton.hasFocus() + "6");
myTextView.setText("图片按钮状态为: Lost Focus");
myImageButton.setImageResource(R.drawable.iconempty);
}


}


}
}

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/white"
    android:orientation="vertical" >


    <TextView
        android:id="@+id/myTextView1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/str_textview1"
        android:textColor="@drawable/blue" />


    <ImageButton
        android:id="@+id/myImageButton1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/iconempty" />


    <Button
        android:id="@+id/myButton1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/str_button1" />


</LinearLayout>


转载地址:http://blog.youkuaiyun.com/jolfe/article/details/9145651

import QtQuick 2.9 Rectangle{ id: imageButton color: "transparent"//"0x6C6C6C" property var images; property int currentIndex:0 property string text: "" property int textOpacity:1 property bool timerEnable: false //是否变化数值后启动定时器 //property bool signal clicked(int index); signal sigBtnLeftOrRight(); signal imageChangeSig(); signal currentModeChangedSig(int mode) //当前模式变换信号 signal sendInfoToServer(int mode) //发送当前数值给服务器 Timer { id: myTimer interval: 100 repeat: false onTriggered: { //console.log("myTimerrrrrrrr", currentIndex) //emit: sendInfoToServer(currentIndex) emit: currentModeChangedSig(currentIndex); //当前模式变换信号 } } Image { id: image asynchronous:false cache: false width: parent.width-20 height: parent.width-20 anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter source: imageButton.images[currentIndex] onSourceChanged: { sourceSize = Qt.size(width, height); // 强制刷新 } } Text { id: desc anchors.top: image.bottom anchors.topMargin: 5 width: parent.width height: 40 text: imageButton.text visible: "" === imageButton.text? false: true font.pixelSize: 23 font.bold: true color:"white" horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignTop opacity: textOpacity font.family: "等线 Light" } MouseArea{ anchors.fill: parent onClicked:{ if (mouse.button == Qt.LeftButton) { imageButton.imageChangeSig(); if (imageButton.currentIndex === 0) { imageButton.currentIndex = 1; desc.color = "#00FF00" } else if(imageButton.currentIndex === 1) { imageButton.currentIndex = 0; desc.color = "white"; } // if (imageButton.currentIndex < imageButton.images.length - 1) // { // imageButton.currentIndex = imageButton.currentIndex + 1; // desc.color = "#00FF00" // } // else // { // imageButton.currentIndex = 0; // desc.color = "white"; // } } } onReleased: { // imageButton.clicked(imageButton.currentIndex); // emit: currentModeChangedSig(imageButton.currentIndex) } /*pressAndHoldInterval: 500 onPressAndHold: { if (imageButton.currentIndex < imageButton.images.length - 1) { imageButton.currentIndex = imageButton.currentIndex + 1; } else { imageButton.currentIndex = 0; } imageButton.clicked(imageButton.currentIndex); }*/ } onCurrentIndexChanged: { if(imageButton.currentIndex === 1) { desc.color = "#00FF00" } else if(imageButton.currentIndex === 0){ desc.color = "white"; } else if(imageButton.currentIndex === 2){ desc.color = "#6C6C6C"; } //image.source = "" image.source = imageButton.images[imageButton.currentIndex] imageButton.clicked(imageButton.currentIndex); emit: currentModeChangedSig(imageButton.currentIndex) } Component.onCompleted: { //console.log("myTimerrrrrrrr", currentIndex) // emit: sendInfoToServer(currentIndex) if(timerEnable) { myTimer.restart() } } } NewImageBtn{ id: daecBtn y:89 width: 120//90 height: 160//90 text:"DAEC" timerEnable: true images:{ var arr = new Array; //arr.push("../../../res/images/daec_off.png"); arr.push(Theme.imageDarkChange); arr.push("../../../res/images/daec_on.png"); return arr; } anchors.horizontalCenter: parent.horizontalCenter }上述代码更新Theme.imageDarkChange时,图像未能及时刷新的原因和解决方案
最新发布
09-29
### 问题分析 在您提供的代码中,`NewImageBtn`(继承自`Rectangle`的自定义按钮组件)的`images`属性中使用了`Theme.imageDarkChange`作为第一个元素。当`Theme.imageDarkChange`更新时,图像未能及时刷新的原因可能包括以下几点: 1. **`source`未正确绑定**: - `Image`的`source`直接绑定到`imageButton.images[currentIndex]`,但`images`是一个动态数组。如果`Theme.imageDarkChange`更新后,`images`数组未重新赋值,`Image`不会感知到变化。 - QML的`Image`组件对`source`的更新依赖属性绑定的通知机制。如果`images`数组的引用未变(即使内容变了),可能不会触发`sourceChanged`信号。 2. **`sourceSize`强制刷新的副作用**: - 您在`onSourceChanged`中设置了`sourceSize = Qt.size(width, height)`,这可能导致图像加载被延迟或覆盖。 3. **`Theme.imageDarkChange`的更新未触发通知**: - 如果`Theme.imageDarkChange`是C++端通过`Q_PROPERTY`暴露的属性,需确保其`NOTIFY`信号正确触发,且QML端能接收到。 --- ### 解决方案 #### 方法1:强制更新`images`数组的引用 在`Theme.imageDarkChange`更新时,重新生成`images`数组,确保属性绑定检测到变化: ```qml // 在Theme.imageDarkChange的更新逻辑中(如C++的setter或QML的onChanged) function updateThemeImage() { daecBtn.images = [ Theme.imageDarkChange, // 动态值 "../../../res/images/daec_on.png" ]; } ``` #### 方法2:直接绑定`Image.source`到`Theme.imageDarkChange` 如果只有第一个图标需要动态切换,可以拆分`images`逻辑: ```qml Image { source: imageButton.currentIndex === 0 ? Theme.imageDarkChange : "../../../res/images/daec_on.png" onSourceChanged: sourceSize = Qt.size(width, height) } ``` #### 方法3:确保`Theme.imageDarkChange`的NOTIFY信号有效 检查C++端的`ThemeManage`类,确认`imageDarkChange`属性的`NOTIFY`信号已定义且触发: ```cpp // ThemeManage.h Q_PROPERTY(QString imageDarkChange READ imageDarkChange NOTIFY imageDarkChangeChanged) // 触发信号的setter void setImageDarkChange(const QString &path) { if (m_imageDarkChange != path) { m_imageDarkChange = path; emit imageDarkChangeChanged(); // 必须触发信号 } } ``` #### 方法4:手动调用`image.source`更新 在`Theme.imageDarkChange`的更新回调中,强制刷新`Image`: ```qml Connections { target: Theme function onImageDarkChangeChanged() { if (daecBtn.currentIndex === 0) { daecBtn.image.source = ""; // 先清空 daecBtn.image.source = Theme.imageDarkChange; // 再赋值 } } } ``` --- ### 推荐实现 结合方法1和方法3,修改后的代码如下: #### 1. 修改`NewImageBtn`的`images`逻辑 ```qml NewImageBtn { id: daecBtn // ...其他属性 images: { var arr = []; arr.push(Theme.imageDarkChange); // 动态绑定 arr.push("../../../res/images/daec_on.png"); return arr; } // 监听Theme变化(如果Theme是全局单例) Connections { target: Theme function onImageDarkChangeChanged() { // 强制更新images数组 var temp = daecBtn.images; daecBtn.images = []; daecBtn.images = temp; } } } ``` #### 2. 确保C++端通知信号 ```cpp // ThemeManage.h signals: void imageDarkChangeChanged(); // 添加信号 // ThemeManage.cpp void ThemeManage::setDarkMode(bool flag) { if (darkMode != flag) { darkMode = flag; emit darkModeChanged(); emit imageDarkChangeChanged(); // 触发图标更新 } } ``` --- ### 关键点总结 1. **动态数组的更新**:QML中数组内容的修改不会自动触发绑定更新,需通过重新赋值数组引用(如`daecBtn.images = []`)或修改数组元素(如`images[0] = newValue`并确保数组是`var`类型)。 2. **NOTIFY信号的必要性**:C++属性变更必须通过信号通知QML。 3. **调试技巧**:在`onSourceChanged`中添加`console.log("Source changed:", source)`,确认是否触发。 --- ### 最终建议 优先使用**方法2**(直接绑定`source`到`Theme.imageDarkChange`),逻辑更清晰且性能更好。如果必须使用数组,则结合**方法1**和**方法3**确保通知机制完整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值