如何在Ubuntu QML应用中设计像微信对话那样的UI

185 篇文章 6 订阅
159 篇文章 2 订阅

我们知道像微信那样的带有气球的对话框对于一些聊天的应用来说非常好。在很多即时通讯的应用中可以用到。在今天的文章中,我们将介绍如何使用QML来实现这样的界面。


为了方便,我们可以采用Ubuntu SDK中的“QtQuick App with QML UI (qmake)”这个模版来实现一个模版的应用。为了能够创建一个TextBalloon的控件,我们使用了C++代码:

textballoon.h


#ifndef TEXTBALLOON_H
#define TEXTBALLOON_H

#include <QtQuick>

class TextBalloon : public QQuickPaintedItem
{
    Q_OBJECT
    Q_PROPERTY(bool rightAligned READ isRightAligned WRITE setRightAligned NOTIFY rightAlignedChanged)

    public:
        TextBalloon(QQuickItem *parent = 0);
        void paint(QPainter *painter);

        bool isRightAligned();
        void setRightAligned(bool rightAligned);

    private:
        bool rightAligned;

    signals:
        void rightAlignedChanged();
};

#endif

textballoon.cpp


#include "textballoon.h"

TextBalloon::TextBalloon(QQuickItem *parent)
    : QQuickPaintedItem(parent)
    , rightAligned(false)
{
}

void TextBalloon::paint(QPainter *painter)
{
    QBrush brush(QColor("#007430"));
    QBrush white(QColor("#FFFFFF"));


    if (rightAligned)
    {
        painter->setBrush(brush);
        painter->setPen(Qt::NoPen);
        painter->setRenderHint(QPainter::Antialiasing);
        painter->drawRoundedRect(10, 0, boundingRect().width() - 19, boundingRect().height(), 10, 10);

        const QPointF points[3] = {
            QPointF(boundingRect().width() - 10.0, 10.0),
            QPointF(boundingRect().width(), 20.0),
            QPointF(boundingRect().width() - 10.0, 30.0),
        };

        painter->drawConvexPolygon(points, 3);
    }
    else
    {
        painter->setBrush(white);
        painter->setPen(Qt::NoPen);
        painter->setRenderHint(QPainter::Antialiasing);
        painter->drawRoundedRect(10, 0, boundingRect().width() - 19, boundingRect().height(), 10, 10);

        const QPointF points[3] = {
            QPointF(10,10),
            QPointF(0, 20),
            QPointF(10, 30),
        };

        painter->drawConvexPolygon(points, 3);
    }
}

bool TextBalloon::isRightAligned()
{
    return this->rightAligned;
}

void TextBalloon::setRightAligned(bool rightAligned)
{
    this->rightAligned = rightAligned;
}


在main.cpp中,注册该类:

   qmlRegisterType<TextBalloon>("TextBalloon", 1, 0, "TextBalloon");

这样这个TextBalloon就可以在QML中被利用。我们的QML界面非常简单:

import QtQuick 2.0
import Ubuntu.Components 1.1


Item {
    id: root

    property int contentWidth: width *.6

    ListModel {
        id: balloonModel
    }

    ListView {
        id: balloonView
        anchors.bottom: controls.top
        anchors.bottomMargin: 2
        anchors.top: parent.top
        clip:true

        delegate: MyDelegate {}

        model: balloonModel
        spacing: units.gu(4)
        width: parent.width
    }

    Rectangle {
        id: controls

        anchors.bottom: parent.bottom
        anchors.left: parent.left
        anchors.margins: 1
        anchors.right: parent.right
        border.width: 2
        color: "white"
        height: parent.height * 0.15

        Text {
            anchors.centerIn: parent
            text: "Add another balloon"
        }

        MouseArea {
            anchors.fill: parent
            hoverEnabled: true
            onClicked: {
                balloonModel.append({"balloonWidth": Math.floor(Math.random() * 200 + 100),
                                     "content": "this is cool"
                                     })
                balloonView.positionViewAtIndex(balloonView.count -1, ListView.End)
            }
            onEntered: {
                parent.color = "#8ac953"
            }
            onExited: {
                parent.color = "white"
            }
        }
    }

    Component.onCompleted: {
        console.log("contentWidth: " + root.contentWidth);
        balloonModel.append({"balloonWidth": root.contentWidth,
                             "content": "this is a text, this is a perfect world to play with, and I love to play the world"
                             });
        balloonModel.append({"balloonWidth": root.contentWidth,
                             "content": "this is a text, this is a perfect world to play with, and I love to play the world"
                             });

    }
}

上面是一个ListView,下面是一个按钮来动态生成一些ListView中的项。我们的ListView的delegate设计稍微麻烦一点:

import QtQuick 2.0
import TextBalloon 1.0
import Ubuntu.Components 1.1
import QtQuick.Layouts 1.1

Item {
    id: delegate
    width: ListView.view.width
    height: txt.contentHeight + 20
    property bool rightAligned: index % 2 == 0 ? false : true

    RowLayout {
        spacing: units.gu(2)
        anchors.right: index % 2 == 0 ? undefined : parent.right

        Image {
            id: leftImg
            width: root.contentWidth*.2
            height: width
            anchors.top:parent.top
            source: "images/pic1.jpg"
            visible: delegate.rightAligned ? false : true
            fillMode: Image.PreserveAspectCrop
            Layout.maximumWidth:root.contentWidth*.2
            Layout.maximumHeight: root.contentWidth*.2
        }

        Text {
            id: txt
            anchors.top: parent.top
            anchors.topMargin: units.gu(1)
            width: root.contentWidth
            wrapMode: Text.WordWrap
            text: content
//            horizontalAlignment: delegate.rightAligned ? Text.AlignRight : Text.AlignLeft
            font.pixelSize: units.gu(3)

            Layout.maximumWidth: root.contentWidth

            TextBalloon {
                anchors.fill: parent
                z: -1
                rightAligned: delegate.rightAligned
                anchors.margins: -units.gu(1.5)
            }
        }

        Image {
            id: rightImg
            anchors.top:parent.top
            width: root.contentWidth*.2
            height: width
            source: "images/pic2.jpg"
            visible: delegate.rightAligned ? true : false
            fillMode: Image.PreserveAspectCrop
            Layout.maximumWidth:root.contentWidth*.2
            Layout.maximumHeight: root.contentWidth*.2
        }
    }
}


这里我们使用RowLayout,也是非常tricky的一个设计。运行我们的应用:

   

整个项目的源码在: https://github.com/liu-xiao-guo/weixin_new

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值