qt for Android使用原生方式和自建类方式实现toast效果

本博介绍个人使用toast心得,现在 还未搞清楚,一点点来,这几天研究这个,目前还未学习qt for Android 的qml使用,暂时也没 时间去研究,所以就简单的先用c++实现,采用qt widget界面方式。toast效果实现两种方式,一种是原生调用,就得构建类去调用java的源代码,还有一种是自己写一种方式去实现toast的效果,下面我会详细介绍两种方式的 纯小白也能学会的创建和使用方式,然后也会附加上例程。

忘了附上参考链接,Qt for Android调用android原生Toast控件Qt for Android调用android原生Toast控件 - Android移动开发技术文章_手机开发 - 红黑联盟

Qt for Android创建AndroidManifest.xml和Java类文件Qt for Android创建AndroidManifest.xml和Java类文件_luoyayun361的博客-CSDN博客_如何建androidmainfest

附上gif效果

最近时间 比较匆忙,在午休空闲之间才能去研究一下qt for Android的各个应用,所以接下来我就以最简单的方式详细的说明 两种方法的创建使用流程。

1.自建仿toast方式

顾名思义,这个就是自己建一个仿真toast的类,在其中写好实现的效果,然后外部需要调用是直接调用这个类的成员函数即可,在此帖最后会放上一个链接,包含源代码,需要的可自行下载参考。(注:此方法也是参考其他帖子下载内容源代码)

创建好子类文件

代码分别如下

stoast.h

// 仿Android的toast提示框
// 适宜将此类实现为多线程下的单例模式

#ifndef STOAST_H
#define STOAST_H

#ifdef Q_OS_WIN32  //Windows 下使用VC++编译器的utf-8字符集解析源码
    #if _MSC_VER  >=1600
        #pragma execution_character_set("utf-8")
    #endif
#endif

 SToast 部分用到
#include <QWidget>
#include <QLabel>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QTimer>
#include <QPainter>
#include <QEvent>
#include <QDesktopWidget>
#include <QApplication>
#include <QPropertyAnimation>

 SingleTonSToast 部分用到
#include <QMutex>
#include <QReadWriteLock>
#include <QAtomicPointer>
#include <QDebug>

class SToast : public QWidget
{
    Q_OBJECT
public:
    explicit SToast(QWidget *parent = 0);
    ~SToast();

    int duration()const;
    void SetDuration(int msec);  //持续显示时间,ms

signals:

public slots:
    void setMessageVDuration(QString msg, int msecDisplayTime=2500);  //消息显示多少毫秒消失

protected:
    void paintEvent(QPaintEvent *event);

private:
    QHBoxLayout *hLayout;
    QVBoxLayout *vLayout;
    QLabel *label;   //提示文字
    QLabel *labIcon; //图标
    int msDuration;  //单位ms
    QTimer durationTimer;
    QPropertyAnimation *animation;

    void fadeInAnimation();   //淡出动画
    void fadeOutAnimation();  //淡入动画

private slots:
    void timeOver();  //定时器超时响应函数
    void fadeInAnimationFinished();  //淡出动画结束响应槽
};

class SingleTonSToast
{
public:
    /*! \brief 用于获得SingleTonSToast实例,使用单例模式。
     *  \return SingleTonSToast实例的引用。
     */
    static /*SingleTonSToast*/SToast &getInstance(void)
    {
#ifndef Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE
        if(!QAtomicPointer</*SingleTonSToast*/SToast>::isTestAndSetNative())  //运行时检测
            qDebug() << "SingleTonSToast类 Error: TestAndSetNative not supported!";
#endif
        //使用双重检测。
        /*! testAndSetOrders操作保证在原子操作前和后的的内存访问
         * 不会被重新排序。
         */
        if(instance.testAndSetOrdered(0, 0)){  //第一次检测
            QMutexLocker locker(&mutex);//加互斥锁。
            instance.testAndSetOrdered(0, new /*SingleTonSToast*/SToast);//第二次检测。
        }

        return *instance;
    }

private:
    SingleTonSToast();  //禁止构造函数。
    SingleTonSToast(const SingleTonSToast &);//禁止拷贝构造函数。
    SingleTonSToast & operator=(const SingleTonSToast &);//禁止赋值拷贝函数。

    QReadWriteLock internalMutex;   //函数使用的读写锁。
    static QMutex mutex;            //实例互斥锁。
    static QAtomicPointer</*SingleTonSToast*/SToast> instance;  /*!<使用原子指针,默认初始化为0。*/
};

#endif // STOAST_H

stoast.cpp

#include "stoast.h"

//静态成员变量初始化。
QMutex SingleTonSToast::mutex;
QAtomicPointer</*SingleTon*/SToast> SingleTonSToast::instance = 0;


SToast::SToast(QWidget *parent) : QWidget(parent)
{
    //初始化成员
    msDuration = 5000;
    animation = new QPropertyAnimation(this, "windowOpacity");

    //初始化窗口属性
    setWindowOpacity(0);  //达到比较好的淡出效果,需要将窗口设置完全透明,否则会有卡顿的效果
    this->setAttribute(Qt::WA_TranslucentBackground,true);  //设置背景透明
    setWindowFlags(Qt::CustomizeWindowHint|Qt::FramelessWindowHint|Qt::Tool|Qt::WindowStaysOnTopHint);
    setStyleSheet("background: black;color: white;border-radius: 5px;");

    //窗口大小及位置属性
    setFixedSize(700,100);  //设置为固定窗口大小达到禁止调节窗口大小
    // Unbtun下有当前桌面扩展,显示的桌面只是逻辑上的一部分,所以看不到居中的效果
    //move((QApplication::desktop()->width() - width())/2,(QApplication::desktop()->height() - height())/2);
    // 此方方法可以解决居中显示的问题
    QRect curDesktopRc = QApplication::desktop()->screenGeometry(this);  //获取显示本窗口的屏幕区域
    move((curDesktopRc.width() - width())/2, (curDesktopRc.height() - height())/8*7); //屏幕居下显示

    //图标、字容器初始化
    //labIcon = new QLabel();
    label = new QLabel();
    label->setFont(QFont("宋体",16));
    label->setAlignment(Qt::AlignCenter);
    label->adjustSize();        //自适应文本
    //label->setWordWrap(true);   //自动折行
    label->setMargin(4);        //边距调整

    //初始化布局
    vLayout = new QVBoxLayout();  //承载文字
    vLayout->addWidget(label);
    vLayout->setAlignment(Qt::AlignCenter);

    hLayout = new QHBoxLayout();  //承载图标和vLayout
    //hLayout->addWidget(labIcon);  预留显示图标
    hLayout->addLayout(vLayout);
    hLayout->setAlignment(Qt::AlignCenter);
    this->setLayout(hLayout);

    //初始化定时器
    connect(&durationTimer, &QTimer::timeout, this, &SToast::timeOver);
}

SToast::~SToast()
{
    delete label; label = NULL;
    delete labIcon; labIcon = NULL;
    delete vLayout; vLayout = NULL;
    delete hLayout; hLayout = NULL;
}

int SToast::duration() const
{
    return msDuration;
}

void SToast::SetDuration(int msec)
{
    msDuration = msec;
}

void SToast::setMessageVDuration(QString msg, int msecDisplayTime/*=2500*/)
{
    // 待完善的功能
    // 1. 对消息进行排队显示,忽略用户指定的显示时间,采用默认的显示时间
    // 2. 对msg的长度适当限制

    this->show();

    if(!msg.isEmpty()){
        label->setText(msg);
    }
    else{
        label->setText("");
    }
    msDuration = msecDisplayTime;

    //淡出画效果
    fadeOutAnimation();

    //开始显示计时
    durationTimer.start(msDuration);
}

void SToast::fadeInAnimation()
{
    //界面动画,改变透明度的方式消失1 - 0渐变
    if(!animation)
        return;
    connect(animation, &QPropertyAnimation::finished, this, &SToast::fadeInAnimationFinished );

    animation->setDuration(1500);
    animation->setStartValue(0.8);
    animation->setEndValue(0);
    //animation->setEasingCurve(QEasingCurve::OutBounce);
    animation->start();
}

void SToast::fadeOutAnimation()
{
    //界面动画,改变透明度的方式出现0 - 1渐变
    if(!animation)
        return;
    animation->setDuration(1500);
    animation->setStartValue(0);
    animation->setEndValue(0.8);
    animation->start();
}

void SToast::timeOver()
{
    durationTimer.stop();

    //测试
    //label->setText("显示时间到,你还有什么想说的吗?");

    //淡入动画效果
    fadeInAnimation();
}

void SToast::fadeInAnimationFinished()
{
    disconnect(animation, &QPropertyAnimation::finished, this, &SToast::fadeInAnimationFinished );
    this->close();
}

void SToast::paintEvent(QPaintEvent *event)
{
    //TODO: coding below


    QWidget::paintEvent(event);
}

其中有些参数是设置固定的,可根据个人需求进行更改,比如,toast显示位置横向在屏幕中间,纵向在屏幕7/8的 位置。。。

接下来就是调用了,在调用函数中首先 要包含其类的头文件,然后调用代码如下

SingleTonSToast::getInstance().setMessageVDuration("自定义类模拟toast测试toast", 2200);

函数的第一个参数是想toast的内容,第二个参数是toast显示的时间2200ms,第一种方法介绍完毕,如果只是简单的应用,不用麻烦的去创建java文件,用此方法即可调用,尤其是可在桌面应用程序中效果更为显著,在Android应用中建议用第二种方式。

2.调用Android原生的toast方法,此种方法只限应用在Android上,在window上无法实现,如果未配置过java的继承类,要配置一下,对于新手来说也算是复杂了,下面详细介绍无到有的步骤。

首先打开一个未配置过的项目,可以看到other files内无AndroidManifest.xml和java文件,没有other files文件夹的朋友也不要慌,不用自己创建,我这个就当 是没有一样一会添加文件会自动有 

放一个我的配置图

编译一下你的qt for Android程序,可以发现在工程目录下

有个android-build文件夹,其中有个AndroidManifest.xml文件是我们需要的。

在工程目录下新建一个文件夹叫aaa,把xml文件放进去,如下

在你的pro文件中添加以下代码,意思是生成apk时会调用aaa文件夹中的AndroidManifest.xml文件

ANDROID_PACKAGE_SOURCE_DIR = $$PWD/aaa

右键你的工程,添加现有文件,选择aaa中的xml文件,就有了以下内容

可以看到AndroidManifest.xml添加进来了,双击xml可配置Android的一些内容,比如图标啊,程序名称啊,也可进入xml程序中配置

可以切换xml程序和此界面。

到此,步骤完成1/3,以后发帖再也不会介绍这个的创建了,因为这是qt for Android最基础的东西了,也是开启qt开发Android的第一步和大门,反反复复介绍也没有必要。

接下里到了qt调用Android原生资源的关键步骤。

在aaa文件夹下的src文件夹下创建一个com文件夹

返回程序,创建新文件

命名随意,看个人,路径选择刚建立的com文件夹下

建立完毕,弹出如下界面,现在界面是空的,没有任何程序,程序运行起来也不会执行到这里,要配置一下,才可以执行这里进而去调用Android原生的一些资源,开启了qt for Android的大门,是从这里进去的。

java文件中添加如下代码

package com.ZtActivity;
import android.content.Intent;
import android.widget.Toast;
import android.os.Handler;
import android.os.Message;
import org.qtproject.qt5.android.bindings.QtActivity;
public class ZtActivity extends org.qtproject.qt5.android.bindings.QtActivity{

    private static ZtActivity m_instance;
    private static Handler m_handler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
             case 1:
                 Toast toast = Toast.makeText(m_instance,(String)msg.obj, Toast.LENGTH_SHORT);
                 toast.show();
                 break;
             };
         }
     };
     public ZtActivity(){
             m_instance = this;
         }
     public static void makeToast(String s){
         m_handler.sendMessage(m_handler.obtainMessage(1, s));
     }

}

第一行的package是很重要的

接下来打开xml文件,选择代码模式,找到划横线的行

后面有句Android:name

将其修改为

配置基本完毕,接下来去配置调用的方式,在pro文件中添加红框中内容,是要调用Android的资源

然后在你想调用toast的函数加上头文件

#include <jni.h>
#include <QAndroidJniObject>
#include <QAndroidJniEnvironment>
#include <QtAndroid>
#include <QDebug>

然后在你想调用的地方加上调用代码,我是在关闭界面closeevent地方加上,用来提示再次按退出按键才退出程序

void Home::closeEvent(QCloseEvent *event)//点击系统自带关闭按钮回调函数
{
    QAndroidJniObject javaToast = QAndroidJniObject::fromString("原生Android测试toast");
        QAndroidJniObject::callStaticMethod<void>("com/ZtActivity/ZtActivity",
                                           "makeToast",
                                           "(Ljava/lang/String;)V",
                                           javaToast.object<jstring>());

   // event->ignore();//失能关闭窗口功能,只能隐藏/显示
}

编译,到手机,很顺利的部署成功

安装到手机上,运行效果如下gif

好了,内容就到这里

附上我的例程源码链接qtforAndroid使用原生方式和自建类方式实现toast效果-Android代码类资源-CSDN下载

对了最后说明一下,实现这个效果的主要目的是可以在一些场合提示一些信息,主要是想在最后一层界面退出程序时,想连续退出两次才会退出程序,第一次退出 只会提示再次点击退出才会退出程序,至于这个效果,相信就很 简单了吧,怎么操作我目前还未写,各位小伙伴自行研究哦

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大桶矿泉水

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值