您的位置:首页 > 产品设计 > UI/UE

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

2015-05-19 19:51 218 查看
我们知道像微信那样的带有气球的对话框对于一些聊天的应用来说非常好。在很多即时通讯的应用中可以用到。在今天的文章中,我们将介绍如何使用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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: