feat: Improve date picker, add select item loop logic

This commit is contained in:
kradchen
2024-09-18 13:06:25 +08:00
parent df7342625e
commit 3f0f05f397
3 changed files with 232 additions and 81 deletions

View File

@@ -13,11 +13,15 @@ DateSlidePickerBox::DateSlidePickerBox(QWidget *parent)
initBox(mHundredYearBox, {"19", "20"}, 56);
QStringList tenYearValues{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
mTenYearBox->setLoop(true);
mYearBox->setLoop(true);
initBox(mTenYearBox, tenYearValues);
initBox(mYearBox, tenYearValues);
addSplitLabel();
mMonthBox->setLoop(true);
QStringList monthValues{"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"};
initBox(mMonthBox, monthValues, 56);
@@ -27,6 +31,7 @@ DateSlidePickerBox::DateSlidePickerBox(QWidget *parent)
for (int i = 13; i <= 31; i++) {
days << QString("%1").arg(i, 2);
}
mDayBox->setLoop(true);
initBox(mDayBox, days, 56);
mBigMonthList.append({"01", "03", "05", "07", "08", "10", "12"});

View File

@@ -6,8 +6,8 @@
#include <QLabel>
#include <qdebug.h>
namespace {
namespace
{
const int LABEL_FONT_SIZE = 80;
const int LABEL_CENTER_Y = 150;
const int LABEL_HEIGHT = 110;
@@ -19,11 +19,7 @@ namespace {
const int SELECTED_AREA_BOTTOM = 200;
}
SlidePickerBox::SlidePickerBox(QWidget *parent)
: QWidget(parent)
, mIsDragging(false)
, mOriginPosY(0)
, mSelectedIndex(0)
, mSelectedLbl(new QLabel(this))
: QWidget(parent), mIsDragging(false), mOriginPosY(0), mSelectedIndex(0), mLoopItem(false), mSelectedLbl(new QLabel(this))
{
this->setFixedHeight(360);
mSelectedLbl->setText("2");
@@ -45,46 +41,115 @@ SlidePickerBox::SlidePickerBox(QWidget *parent)
linePlaceholderWidget->move(lp);
}
void SlidePickerBox::mousePressEvent(QMouseEvent * ev) {
void SlidePickerBox::mousePressEvent(QMouseEvent *ev)
{
mIsDragging = true;
mOriginPosY = ev->pos().y();
QWidget::mousePressEvent( ev);
QWidget::mousePressEvent(ev);
}
void SlidePickerBox::mouseMoveEvent(QMouseEvent *ev) {
//只有一个label无需滑动
if (mLabels.count() < 2) return;
if (nullptr == mSelectedLbl) return;
void SlidePickerBox::mouseMoveEvent(QMouseEvent *ev)
{
// 只有一个label无需滑动
if (mLabels.count() < 2)
return;
if (nullptr == mSelectedLbl)
return;
if (mIsDragging)
{
int offset = (ev->pos().y() - mOriginPosY);
//防止速度过快
while(abs(offset)>50)
// 防止速度过快
while (abs(offset) > 50)
{
offset=offset/2;
offset = offset / 2;
}
//防止拉过头
// 防止拉过头
int selItemCenterY = mSelectedLbl->geometry().center().y();
if (mSelectedLbl == getEnabledLastLabel() && selItemCenterY <= LABEL_CENTER_Y && offset < 0) return;
if (mSelectedLbl == getEnabledFirstLabel() && selItemCenterY >= LABEL_CENTER_Y && offset > 0) return;
int i = 0;
for (auto item : mLabels)
if (!mLoopItem || mLabels.count() < 3)
{
if (mDisabledItems.contains(item->text()))continue;
//不需要横向,只需要纵向
int ny = item->geometry().top() + offset;
item->move(item->geometry().left(),ny);
int centerY = item->geometry().center().y();
if (centerY <= SELECTED_AREA_BOTTOM+5
&& centerY > SELECTED_AREA_TOP-5)
if (mSelectedLbl == getEnabledLastLabel() && selItemCenterY <= LABEL_CENTER_Y && offset < 0)
return;
if (mSelectedLbl == getEnabledFirstLabel() && selItemCenterY >= LABEL_CENTER_Y && offset > 0)
return;
int i = 0;
for (auto item : mLabels)
{
item->setStyleSheet("color:white");
mSelectedLbl = item;
mSelectedIndex = i;
} else{
item->setStyleSheet("background:transparent");
if (mDisabledItems.contains(item->text()))
continue;
// 不需要横向,只需要纵向
int ny = item->geometry().top() + offset;
item->move(item->geometry().left(), ny);
int centerY = item->geometry().center().y();
// new in selectd area
if (centerY <= SELECTED_AREA_BOTTOM + 5 && centerY > SELECTED_AREA_TOP - 5)
{
item->setStyleSheet("color:white");
mSelectedLbl = item;
mSelectedIndex = i;
}
else
{
item->setStyleSheet("background:transparent");
}
i++;
}
}
else
{
int newSelectedIndex = 0;
for (int i = 0; i<mLabels.count(); i++)
{
if (mDisabledItems.contains(mLabels[i]->text()))
continue;
// 不需要横向,只需要纵向
int ny = mLabels[i]->geometry().top() + offset;
mLabels[i]->move(mLabels[i]->geometry().left(), ny);
int centerY = mLabels[i]->geometry().center().y();
// new in selectd area
if (centerY <= SELECTED_AREA_BOTTOM + 5 && centerY > SELECTED_AREA_TOP - 5)
{
mSelectedLbl->setStyleSheet("background:transparent");
mSelectedLbl = mLabels[i];
newSelectedIndex = i;
}
}
mSelectedLbl->setStyleSheet("color:white");
if (newSelectedIndex > mSelectedIndex)
{
auto lastVisibelBack = mLabels.back();
int i = mLabels.length()-2;
while (!lastVisibelBack->isVisible())
{
lastVisibelBack = mLabels[i--];
}
do
{
auto first = mLabels.first();
mLabels.pop_front();
mLabels.push_back(first);
} while (!mLabels.back()->isVisible());
mLabels.back()->move(lastVisibelBack->geometry().left(),
lastVisibelBack->geometry().top()+LABEL_HEIGHT);
}
else if(newSelectedIndex < mSelectedIndex)
{
auto lastVisibelFirst = mLabels.first();
int i = 1;
while (!lastVisibelFirst->isVisible())
{
lastVisibelFirst = mLabels[i++];
}
do
{
auto back = mLabels.back();
mLabels.pop_back();
mLabels.push_front(back);
} while (!mLabels.first()->isVisible());
mLabels.first()->move(lastVisibelFirst->geometry().left(),
lastVisibelFirst->geometry().top()-LABEL_HEIGHT);
}
i++;
}
mOriginPosY = ev->pos().y();
repaint();
@@ -92,33 +157,36 @@ void SlidePickerBox::mouseMoveEvent(QMouseEvent *ev) {
QWidget::mouseMoveEvent(ev);
}
void SlidePickerBox::mouseReleaseEvent(QMouseEvent *ev) {
void SlidePickerBox::mouseReleaseEvent(QMouseEvent *ev)
{
mIsDragging = false;
adjustPosition();
QWidget::mouseReleaseEvent(ev);
QString v = getSelectedValue();
emit valueChanged(v);
}
void SlidePickerBox::adjustPosition() const
{
void SlidePickerBox::adjustPosition() const {
if(mSelectedLbl == nullptr)
if (mSelectedLbl == nullptr)
{
return;
}
if (mSelectedLbl->geometry().center().y() != LABEL_CENTER_Y)
{
//选择完毕,选中项回归正位
// 选择完毕,选中项回归正位
int offset = LABEL_CENTER_Y - mSelectedLbl->geometry().center().y();
for (auto item : mLabels)
{
int ny = item->geometry().top()+offset;
item->move(item->geometry().left(),ny);
int ny = item->geometry().top() + offset;
item->move(item->geometry().left(), ny);
}
}
}
void SlidePickerBox::setItems(const QStringList& itemsList) {
void SlidePickerBox::setItems(const QStringList &itemsList)
{
this->mItems = itemsList;
hideLabel(mSelectedLbl);
for (auto item : mLabels)
@@ -127,8 +195,8 @@ void SlidePickerBox::setItems(const QStringList& itemsList) {
}
mSelectedLbl = nullptr;
mLabels.clear();
QPoint p = {MARGIN_LEFT,-LABEL_CENTER_Y};
for (const QString& str : this->mItems)
QPoint p = {MARGIN_LEFT, -LABEL_CENTER_Y};
for (const QString &str : this->mItems)
{
auto lbl = new QLabel(this);
lbl->setText(str);
@@ -140,21 +208,42 @@ void SlidePickerBox::setItems(const QStringList& itemsList) {
mLabels.push_back(lbl);
lbl->move(p);
}
mSelectedIndex = mLabels.count() - 1;
if(!mItems.isEmpty())
if (!mLoopItem || mLabels.count() <= 3)
{
setSelectedValue(this->mItems.last());
mSelectedIndex = mLabels.count() - 1;
if (!mItems.isEmpty())
{
setSelectedValue(this->mItems.last());
}
}
else
{
mSelectedIndex = (mLabels.count() + 1) / 2;
if (!mItems.isEmpty())
{
setSelectedValue(mLabels[mSelectedIndex]->text());
}
}
}
QString SlidePickerBox::getSelectedValue() {
if (!mSelectedLbl) return "";
void SlidePickerBox::setLoop(bool aIsLoop)
{
mLoopItem = aIsLoop;
}
QString SlidePickerBox::getSelectedValue()
{
if (!mSelectedLbl)
return "";
return mSelectedLbl->text();
}
void SlidePickerBox::setCurrentLabel(QLabel *label) {
if (mSelectedLbl)hideLabel(mSelectedLbl);
if (label) {
void SlidePickerBox::setCurrentLabel(QLabel *label)
{
if (mSelectedLbl)
hideLabel(mSelectedLbl);
if (label)
{
QPoint p = {MARGIN_LEFT, MARGIN_TOP};
label->move(p);
label->show();
@@ -162,47 +251,92 @@ void SlidePickerBox::setCurrentLabel(QLabel *label) {
}
}
QLabel * SlidePickerBox::getEnabledFirstLabel() {
if (mDisabledItems.empty()) return mLabels.first();
for(int idx = 0; idx < mDisabledItems.size(); ++idx){
if(mDisabledItems.contains(mLabels[idx]->text()))continue;
QLabel *SlidePickerBox::getEnabledFirstLabel()
{
if (mDisabledItems.empty())
return mLabels.first();
for (int idx = 0; idx < mDisabledItems.size(); ++idx)
{
if (mDisabledItems.contains(mLabels[idx]->text()))
continue;
return mLabels[idx];
}
return nullptr;
}
QLabel * SlidePickerBox::getEnabledLastLabel() {
if (mDisabledItems.empty()) return mLabels.last();
for(int idx = mLabels.size() - 1; idx >= 0; --idx){
if(mDisabledItems.contains(mLabels[idx]->text()))continue;
QLabel *SlidePickerBox::getEnabledLastLabel()
{
if (mDisabledItems.empty())
return mLabels.last();
for (int idx = mLabels.size() - 1; idx >= 0; --idx)
{
if (mDisabledItems.contains(mLabels[idx]->text()))
continue;
return mLabels[idx];
}
return nullptr;
}
void SlidePickerBox::hideLabel(QLabel *label) {
if (!label) return;
void SlidePickerBox::hideLabel(QLabel *label)
{
if (!label)
return;
QPoint p = {MARGIN_LEFT, -LABEL_CENTER_Y};
label->move(p);
}
void SlidePickerBox::setSelectedValue(const QString& val) {
for (int i = 0; i < mLabels.count() ; ++i) {
if(mLabels[i]->text() == val) {
mSelectedIndex = i;
break;
void SlidePickerBox::setSelectedValue(const QString &val)
{
if (!mLoopItem || mLabels.count() <= 3)
{
for (int i = 0; i < mLabels.count(); ++i)
{
if (mLabels[i]->text() == val)
{
mSelectedIndex = i;
break;
}
}
}
int firstLabelY = -LABEL_HEIGHT * (mSelectedIndex - 1);
for (int i = 0; i < mLabels.count() ; ++i) {
else
{
int newSelectIndex = 0;
for (int i = 0; i < mLabels.count(); ++i)
{
if (mLabels[i]->text() == val)
{
newSelectIndex = i;
break;
}
}
bool step = newSelectIndex > mSelectedIndex;
int round = abs(newSelectIndex - mSelectedIndex);
for (int i = 0; i < round; i++)
{
if (step)
{
auto item = mLabels.first();
mLabels.pop_front();
mLabels.push_back(item);
}
else
{
auto item = mLabels.back();
mLabels.pop_back();
mLabels.push_front(item);
}
}
}
int firstLabelY = -LABEL_HEIGHT * (mSelectedIndex-1);
for (int i = 0; i < mLabels.count(); ++i)
{
QPoint leftPoint = this->mapTo(this, {MARGIN_LEFT, firstLabelY + i * LABEL_HEIGHT});
mLabels[i]->move(leftPoint);
mLabels[i]->show();
mLabels[i]->setStyleSheet("background:transparent");
}
if(mSelectedIndex >= 0)
if (mSelectedIndex >= 0)
{
mSelectedLbl = mLabels[mSelectedIndex];
mLabels[mSelectedIndex]->setStyleSheet("color:white");
@@ -210,33 +344,42 @@ void SlidePickerBox::setSelectedValue(const QString& val) {
adjustPosition();
}
void SlidePickerBox::resizeLabelWidth() {
for (int i = 0; i < mLabels.count() ; ++i) {
void SlidePickerBox::resizeLabelWidth()
{
for (int i = 0; i < mLabels.count(); ++i)
{
mLabels[i]->setAlignment(Qt::AlignCenter);
mLabels[i]->setFixedWidth(this->width() + this->contentsMargins().left() + this->contentsMargins().right());
}
}
void SlidePickerBox::disableItem(const QString& val) {
if (!mDisabledItems.contains(val)){
void SlidePickerBox::disableItem(const QString &val)
{
if (!mDisabledItems.contains(val))
{
mDisabledItems.append(val);
rearrangeLabels();
}
}
void SlidePickerBox::enableItem(const QString &val) {
if (mDisabledItems.contains(val)){
void SlidePickerBox::enableItem(const QString &val)
{
if (mDisabledItems.contains(val))
{
mDisabledItems.removeOne(val);
rearrangeLabels();
}
}
void SlidePickerBox::rearrangeLabels() {
void SlidePickerBox::rearrangeLabels()
{
int firstLabelY = -100 * (mSelectedIndex - 1);
int visibleItemIndex = 0;
for (int i = 0; i < mLabels.count() ; ++i) {
if (mDisabledItems.contains(mLabels[i]->text())){
mLabels[i]->hide();
for (int i = 0; i < mLabels.count(); ++i)
{
if (mDisabledItems.contains(mLabels[i]->text()))
{
mLabels[i]->setVisible(false);
continue;
}
QPoint p = this->mapTo(this, {MARGIN_LEFT, firstLabelY + visibleItemIndex * LABEL_HEIGHT});
@@ -249,4 +392,3 @@ void SlidePickerBox::rearrangeLabels() {
mLabels[mSelectedIndex]->setStyleSheet("color:white");
adjustPosition();
}

View File

@@ -2,6 +2,7 @@
#define GUI_SLIDEPICKERBOX_H
#include <QWidget>
#include <QLinkedList>
class QLabel;
class SlidePickerBox:public QWidget {
Q_OBJECT
@@ -9,6 +10,8 @@ public:
explicit SlidePickerBox(QWidget *parent = nullptr);
QString getSelectedValue();
void setItems(const QStringList& itemsList);
void setLoop(bool isLoop);
void addItem(QString& item) {
this->mItems.append(item);
}
@@ -37,6 +40,7 @@ protected:
private:
int mOriginPosY;
int mSelectedIndex;
bool mLoopItem;
QLabel* mSelectedLbl;
QList<QLabel*> mLabels;
QStringList mItems;