隨着移動互聯網的盛行,如今手機APP大行其道,每一個人的手機沒有十幾個APP都很差意思說本身是現代人,各類聊天、購物、直播、小視頻等APP,有個陌生人社交的APP叫探探,本人用過幾回,固然不是去爲了找對象,而是純粹爲了好玩研究下他的U設計和軟件邏輯流程等,其中有個雷達控件,單擊之後能夠搜索附近的異性進行配對,這個雷達控件的效果蠻好的,因而手癢琢磨着用Qt來實現一個,畢竟本身寫了150多個控件了,已經上癮了,對各類效果都如魚得水,看到各類效果都不天然的想到編碼思路等。 這個控件的核心其實就是外圍的那個掃描圈和發散的掃描線,中間變大變小恢復正常的圓形頭像,外圍的掃描圈採用錐形漸變顏色,經過透明度控制造成掃描效果,核心方法就是drawPie,至於擴散圈,須要識別到單擊之後將擴散圈存入隊列,由於可能會單擊屢次,產生多個擴散圈,至於中間頭像的動態效果,採用三個QPropertyAnimation來實現,一個負責變大,一個負責變小,一個負責恢復正常,而後三個動畫加入到QSequentialAnimationGroup動畫序列中,按照順序執行。linux
#ifndef SCANTANTAN_H #define SCANTANTAN_H /** * 探探雷達控件 做者:東門吹雪(QQ:709102202) 整理:feiyangqingyun(QQ:517216493) 2019-10-01 * 1:可設置中間圖像 * 2:可設置圖像的邊框寬度+邊框顏色,產生圓形圖像效果 * 3:可設置掃描線的最大半徑 * 4:可設置掃描線的邊框寬度 * 5:可設置擴散圈的線條寬度 * 6:可設置掃描線的每次移動的步長 * 7:可設置擴散圈的每次移動的步長 * 8:可設置掃描線的顏色 * 9:可設置擴散圈的顏色 */ #include <QWidget> class QSequentialAnimationGroup; #ifdef quc #if (QT_VERSION < QT_VERSION_CHECK(5,7,0)) #include <QtDesigner/QDesignerExportWidget> #else #include <QtUiPlugin/QDesignerExportWidget> #endif class QDESIGNER_WIDGET_EXPORT ScanTanTan : public QWidget #else class ScanTanTan : public QWidget #endif { Q_OBJECT Q_PROPERTY(QPixmap image READ getImage WRITE setImage) Q_PROPERTY(int imageBorderWidth READ getImageBorderWidth WRITE setImageBorderWidth) Q_PROPERTY(QColor imageBorderColor READ getImageBorderColor WRITE setImageBorderColor) Q_PROPERTY(int scanRadius READ getScanRadius WRITE setScanRadius) Q_PROPERTY(int scanWidth READ getScanWidth WRITE setScanWidth) Q_PROPERTY(int ringWidth READ getRingWidth WRITE setRingWidth) Q_PROPERTY(int scanStep READ getScanStep WRITE setScanStep) Q_PROPERTY(int ringStep READ getRingStep WRITE setRingStep) Q_PROPERTY(QColor scanColor READ getScanColor WRITE setScanColor) Q_PROPERTY(QColor ringColor READ getRingColor WRITE setRingColor) public: struct RingData { int radius; //半徑 float width; //畫筆粗細 int alpha; //透明度 }; explicit ScanTanTan(QWidget *parent = 0); protected: void mousePressEvent(QMouseEvent *); void mouseReleaseEvent(QMouseEvent *); void paintEvent(QPaintEvent *); void drawScan(QPainter *painter); void drawRing(QPainter *painter); void drawImage(QPainter *painter); private slots: void changeScan(); void changeRing(); void updateImage(const QVariant &value); double twoPtDistance(const QPointF &pt1, const QPointF &pt2); private: QPixmap image; //中間圖片 int imageBorderWidth; //圖片邊框寬度 QColor imageBorderColor;//圖片邊框顏色 int scanRadius; //掃描線最大半徑 int scanWidth; //掃描線邊框寬度 int ringWidth; //擴散圈線條寬度 int scanStep; //掃描線每次移動的步長 int ringStep; //擴散圈每次移動的步長 QColor scanColor; //掃描線顏色 QColor ringColor; //擴散圈顏色 bool isPressed; //鼠標是否按下 int ringRadius; //擴散圈半徑 int imageRadius; //圖片半徑 int scanDeg; //當前掃描線角度 //擴散圈集合,鼠標可能按下屢次則產生多個擴散圈,用隊列存起來 QList<RingData> rings; //動畫組合,用於中間圖片的變大放小 QSequentialAnimationGroup *animationGroup; public: QPixmap getImage() const; int getImageBorderWidth() const; QColor getImageBorderColor()const; int getScanRadius() const; int getScanWidth() const; int getRingWidth() const; int getScanStep() const; int getRingStep() const; QColor getScanColor() const; QColor getRingColor() const; QSize sizeHint() const; QSize minimumSizeHint() const; public Q_SLOTS: //設置圖片+圖片邊框寬度+圖片邊框顏色 void setImage(const QPixmap &image); void setImageBorderWidth(int imageBorderWidth); void setImageBorderColor(const QColor &imageBorderColor); //設置掃描線最大半徑+掃描線邊框寬度+擴散圈線條寬度 void setScanRadius(int scanRadius); void setScanWidth(int scanWidth); void setRingWidth(int ringWidth); //設置掃描線步長+擴散圈步長 void setScanStep(int scanStep); void setRingStep(int ringStep); //設置掃描線顏色+擴散圈顏色 void setScanColor(const QColor &scanColor); void setRingColor(const QColor &ringColor); }; #endif // SCANTANTAN_H
void ScanTanTan::paintEvent(QPaintEvent *) { int width = this->width(); int height = this->height(); int side = qMin(width, height); //繪製準備工做,啓用反鋸齒,平移座標軸中心,等比例縮放 QPainter painter(this); painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); painter.translate(width / 2, height / 2); painter.scale(side / 200.0, side / 200.0); //繪製掃描線 drawScan(&painter); //繪製擴散圈 drawRing(&painter); //繪製中間圖片 drawImage(&painter); } void ScanTanTan::drawScan(QPainter *painter) { painter->save(); //錐形漸變顏色,經過透明度控制造成掃描效果 QConicalGradient conicalGradient(0, 0, scanDeg); QColor color = scanColor; color.setAlpha(50); conicalGradient.setColorAt(0, color); color.setAlpha(0); conicalGradient.setColorAt(1, color); //設置畫筆畫刷 QPen pen; pen.setWidth(scanWidth); pen.setBrush(conicalGradient); painter->setPen(pen); painter->setBrush(conicalGradient); //繪製餅圓 QRect rect(-scanRadius, -scanRadius, scanRadius * 2, scanRadius * 2); painter->drawPie(rect, scanDeg * 16, 360 * 16); painter->restore(); } void ScanTanTan::drawRing(QPainter *painter) { painter->save(); painter->setBrush(Qt::NoBrush); //繪製全部擴散圈,擴散圈其實就是個沒有背景顏色的圓形 for (int i = 0; i < rings.count(); i++) { RingData ring = rings.at(i); int radius = ring.radius; float width = ring.width; int alpha = 255 - ring.alpha; QColor color = ringColor; color.setAlpha(alpha); QPen pen; pen.setWidthF(width); pen.setColor(color); painter->setPen(pen); painter->drawEllipse(-radius, -radius, radius * 2, radius * 2); } painter->restore(); } void ScanTanTan::drawImage(QPainter *painter) { painter->save(); //設置圓形遮罩路徑,產生圓形頭像效果 QPainterPath path; path.addEllipse(QPoint(0, 0), imageRadius, imageRadius); painter->setClipPath(path); //繪製圖片 QRect rect(-imageRadius, -imageRadius, imageRadius * 2, imageRadius * 2); painter->drawPixmap(rect, image); //繪製圖片邊緣圓形 QPen pen; pen.setWidth(imageBorderWidth); pen.setColor(imageBorderColor); painter->setPen(pen); painter->setBrush(Qt::NoBrush); //如下兩種方法二選一,其實繪製360度的圓弧=繪製無背景的圓形 //painter->drawArc(rect, 0, 360 * 16); painter->drawEllipse(rect); painter->restore(); }