Commit 3bebf347 by Wyh

Merge remote-tracking branch 'origin/master'

parents da93bfc3 8dbe5c8f
.idea
.DS_Store
local.properties
/*.iml
/build
apply plugin: 'java-library'
dependencies {
def lintVersion = '26.4.2'
compileOnly "com.android.tools.lint:lint-api:$lintVersion"
compileOnly "com.android.tools.lint:lint-checks:$lintVersion"
}
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
jar {
manifest {
attributes("Lint-Registry-v2": 'com.qmuiteam.qmui.lint.QMUIIssueRegistry')
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.lint;
import com.android.tools.lint.client.api.JavaEvaluator;
import com.android.tools.lint.client.api.UElementHandler;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.JavaContext;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
import com.google.common.collect.Lists;
import com.intellij.psi.PsiMethod;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.uast.UCallExpression;
import org.jetbrains.uast.UElement;
import org.jetbrains.uast.UExpression;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
/**
* 检测 QMUILog 中是否使用了 F Word。
* Created by Kayo on 2017/9/19.
*/
public class QMUIFWordDetector extends Detector implements Detector.UastScanner {
public static final Issue ISSUE_F_WORD =
Issue.create("QMUIDontUseTheFWordInLog",
"Please, don't use the f word, type something more nicely.",
"Do I need to explain this? \uD83D\uDD95",
Category.CORRECTNESS, 5, Severity.WARNING,
new Implementation(QMUIFWordDetector.class, EnumSet.of(Scope.JAVA_FILE)));
@Nullable
@Override
public List<Class<? extends UElement>> getApplicableUastTypes() {
return Lists.<Class<? extends UElement>>newArrayList(
UCallExpression.class);
}
@Nullable
@Override
public UElementHandler createUastHandler(@NotNull JavaContext context) {
return new FWordHandler(context);
}
static class FWordHandler extends UElementHandler {
private static final List<String> checkMedthods = Arrays.asList("e", "w", "i", "d");
private static final List<String> fWords = Arrays.asList("fuck", "bitch", "bullshit");
private JavaContext mJavaContext;
FWordHandler(@NotNull JavaContext context) {
mJavaContext = context;
}
@Override
public void visitCallExpression(@NotNull UCallExpression node) {
JavaEvaluator evaluator = mJavaContext.getEvaluator();
PsiMethod method = node.resolve();
if (evaluator.isMemberInClass(method, "android.util.Log") ||
evaluator.isMemberInClass(method, "com.qmuiteam.qmui.QMUILog")) {
String methodName = node.getMethodName();
if (checkMedthods.contains(methodName)) {
List<UExpression> expressions = node.getValueArguments();
for (UExpression expression : expressions) {
String text = expression.asRenderString();
for(String fword: fWords){
int index = text.indexOf(fword);
if(index >= 0){
mJavaContext.report(
ISSUE_F_WORD, expression,
mJavaContext.getRangeLocation(expression, index, fword.length()), "\uD83D\uDD95");
}
}
}
}
}
}
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.lint;
import com.android.resources.ResourceFolderType;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.Location;
import com.android.tools.lint.detector.api.ResourceContext;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
/**
* 检测图片的尺寸的正确性,例如2倍图的宽高应该为偶数,3倍图的宽高应该为3的倍数
* Created by Kayo on 2017/9/7.
*/
public class QMUIImageScaleDetector extends Detector implements Detector.BinaryResourceScanner {
public static final Issue ISSUE_IMAGE_SCALE =
Issue.create("QMUIImageSizeDisproportionate",
"The size of this image is disproportionate.",
"Please check the size of the image, for example, the height and width of the 3x plot should be 1.5 times 2x plot.",
Category.ICONS, 4, Severity.WARNING,
new Implementation(QMUIImageScaleDetector.class, Scope.BINARY_RESOURCE_FILE_SCOPE));
private static final String IGNORE_IMAGE_NIGHT_PNG = ".9.png";
private static final String CHECK_IMAGE_WEBP = ".webp";
private static final String CHECK_IMAGE_PNG = ".png";
private static final String CHECK_IMAGE_JPEG = ".jpeg";
private static final String CHECK_IMAGE_JPG = ".jpg";
@Override
public boolean appliesTo(ResourceFolderType var1) {
return var1.getName().equalsIgnoreCase(String.valueOf(ResourceFolderType.MIPMAP)) || var1.getName().equalsIgnoreCase(String.valueOf(ResourceFolderType.DRAWABLE));
}
@Override
public void checkBinaryResource(ResourceContext context) {
String filename = context.file.getName();
if (filename.contains(IGNORE_IMAGE_NIGHT_PNG)) {
return;
}
if (filename.contains(CHECK_IMAGE_WEBP) || filename.contains(CHECK_IMAGE_PNG) || filename.contains(CHECK_IMAGE_JPEG) || filename.contains(CHECK_IMAGE_JPG)) {
String filePath = context.file.getPath();
String pattern = ".*?[mipmap|drawable]\\-xhdpi.*?";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(filePath);
if (m.find()) {
String threePlotFilePath = filePath.replace("xhdpi", "xxhdpi");
File threePlotFile = new File(threePlotFilePath);
try {
BufferedImage targetImage = ImageIO.read(context.file);
int targetWidth = targetImage.getWidth();
int targetHeight = targetImage.getHeight();
BufferedImage threePlotImage = ImageIO.read(threePlotFile);
int threePlotWidth = threePlotImage.getWidth();
int threePlotHeight = threePlotImage.getHeight();
if ((double) threePlotWidth / targetWidth != 1.5 || (double) threePlotHeight / targetHeight != 1.5) {
Location fileLocation = Location.create(context.file);
context.report(ISSUE_IMAGE_SCALE, fileLocation, "2倍图 " + filePath +
" 与其3倍图宽高分别为 (" + targetWidth + ", " + targetHeight + ") 和 (" + threePlotWidth + ", " + threePlotHeight + "),不符合比例关系。");
}
} catch (Exception ignored) {
}
}
}
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.lint;
import com.android.resources.ResourceFolderType;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.Location;
import com.android.tools.lint.detector.api.ResourceContext;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
import java.awt.image.BufferedImage;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
/**
* 检测图片的尺寸的正确性,例如2倍图的宽高应该为偶数,3倍图的宽高应该为3的倍数
* Created by Kayo on 2017/8/30.
*/
public class QMUIImageSizeDetector extends Detector implements Detector.BinaryResourceScanner {
public static final Issue ISSUE_IMAGE_SIZE =
Issue.create("QMUIImageSizeInvalid",
"The size of this image is not correct.",
"Please check the size of the image, for example, the height and width of the 2x plot should be even.",
Category.ICONS, 2, Severity.WARNING,
new Implementation(QMUIImageSizeDetector.class, Scope.BINARY_RESOURCE_FILE_SCOPE));
private static final String IGNORE_IMAGE_NIGHT_PNG = ".9.png";
private static final String CHECK_IMAGE_WEBP = ".webp";
private static final String CHECK_IMAGE_PNG = ".png";
private static final String CHECK_IMAGE_JPEG = ".jpeg";
private static final String CHECK_IMAGE_JPG = ".jpg";
/**
* 去掉数值多余的0与小数点符号
*/
public static String trimZeroAndDot(double number) {
String value = String.valueOf(number);
if (value.indexOf(".") > 0) {
value = value.replaceAll("0+?$", ""); // 去掉多余的0
value = value.replaceAll("[.]$", ""); // 若此时最后一位是小数点符号,则去掉该符号
}
return value;
}
@Override
public boolean appliesTo(ResourceFolderType var1) {
return var1.getName().equalsIgnoreCase(String.valueOf(ResourceFolderType.MIPMAP)) || var1.getName().equalsIgnoreCase(String.valueOf(ResourceFolderType.DRAWABLE));
}
@Override
public void checkBinaryResource(ResourceContext context) {
String filename = context.file.getName();
if (filename.contains(IGNORE_IMAGE_NIGHT_PNG)) {
return;
}
if (filename.contains(CHECK_IMAGE_WEBP) || filename.contains(CHECK_IMAGE_PNG) || filename.contains(CHECK_IMAGE_JPEG) || filename.contains(CHECK_IMAGE_JPG)) {
String filePath = context.file.getPath();
String pattern = ".*?[mipmap|drawable]\\-(x*)hdpi.*?";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(filePath);
if (m.find()) {
double multiple = 1.5;
if (m.group(1).length() > 0) {
multiple = m.group(1).length() + 1;
}
try {
BufferedImage targetImage = ImageIO.read(context.file);
int width = targetImage.getWidth();
int height = targetImage.getHeight();
if (width % multiple != 0 || height % multiple != 0) {
Location fileLocation = Location.create(context.file);
context.report(ISSUE_IMAGE_SIZE, fileLocation, filePath + " 为" + trimZeroAndDot(multiple) + "倍图,其宽高应该是" + trimZeroAndDot(multiple) + "的倍数,目前宽高为 (" + width + ", " + height + ")。");
}
} catch (Exception ignored) {
}
}
}
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.lint;
import com.android.tools.lint.client.api.IssueRegistry;
import com.android.tools.lint.detector.api.Issue;
import java.util.Arrays;
import java.util.List;
import static com.android.tools.lint.detector.api.ApiKt.CURRENT_API;
@SuppressWarnings("unused")
public final class QMUIIssueRegistry extends IssueRegistry {
@Override public List<Issue> getIssues() {
return Arrays.asList(
QMUIFWordDetector.ISSUE_F_WORD,
QMUIJavaVectorDrawableDetector.ISSUE_JAVA_VECTOR_DRAWABLE,
QMUIXmlVectorDrawableDetector.ISSUE_XML_VECTOR_DRAWABLE,
QMUIImageSizeDetector.ISSUE_IMAGE_SIZE,
QMUIImageScaleDetector.ISSUE_IMAGE_SCALE
);
}
@Override
public int getApi() {
return CURRENT_API;
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.lint;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.JavaContext;
import com.android.tools.lint.detector.api.Project;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
import com.intellij.psi.JavaElementVisitor;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiExpressionList;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiMethodCallExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.List;
/**
* 检测是否在 getDrawable 方法中传入了 Vector Drawable,在 4.0 及以下版本的系统中会导致 Crash
* Created by Kayo on 2017/8/24.
*/
public class QMUIJavaVectorDrawableDetector extends Detector implements Detector.UastScanner {
public static final Issue ISSUE_JAVA_VECTOR_DRAWABLE =
Issue.create("QMUIGetVectorDrawableWithWrongFunction",
"Should use the corresponding method to get vector drawable.",
"Using the normal method to get the vector drawable will cause a crash on Android versions below 4.0",
Category.CORRECTNESS, 8, Severity.ERROR,
new Implementation(QMUIJavaVectorDrawableDetector.class, Scope.JAVA_FILE_SCOPE));
@Override
public List<String> getApplicableMethodNames() {
return Collections.singletonList("getDrawable");
}
@Override
public void visitMethod(@NotNull JavaContext context,
@Nullable JavaElementVisitor visitor,
@NotNull PsiMethodCallExpression call,
@NotNull PsiMethod method) {
super.visitMethod(context, visitor, call, method);
PsiExpressionList args = call.getArgumentList();
if (args.getExpressions().length == 0) {
return;
}
Project project = context.getProject();
List<File> resourceFolder = project.getResourceFolders();
if (resourceFolder.isEmpty()) {
return;
}
String resourcePath = resourceFolder.get(0).getAbsolutePath();
for (PsiExpression expression : args.getExpressions()) {
String input = expression.toString();
if (input != null && input.contains("R.drawable")) {
// 找出 drawable 相关的参数
// 获取 drawable 名字
String drawableName = input.replace("R.drawable.", "");
try {
// 若 drawable 为 Vector Drawable,则文件后缀为 xml,根据 resource 路径,drawable 名字,文件后缀拼接出完整路径
FileInputStream fileInputStream = new FileInputStream(resourcePath + "/drawable/" + drawableName + ".xml");
BufferedReader reader = new BufferedReader(new InputStreamReader(fileInputStream));
String line = reader.readLine();
if (line.contains("vector")) {
// 若文件存在,并且包含首行包含 vector,则为 Vector Drawable,抛出警告
context.report(ISSUE_JAVA_VECTOR_DRAWABLE, method, context.getLocation(method), expression.toString() + " 为 Vector Drawable,请使用 getVectorDrawable 方法获取,避免 4.0 及以下版本的系统产生 Crash");
}
reader.close();
fileInputStream.close();
} catch (Exception ignored) {
}
}
}
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.lint;
import com.android.annotations.NonNull;
import com.android.resources.ResourceFolderType;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.Project;
import com.android.tools.lint.detector.api.ResourceXmlDetector;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
import com.android.tools.lint.detector.api.XmlContext;
import com.google.common.collect.Lists;
import org.w3c.dom.Attr;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.List;
import static com.android.SdkConstants.ATTR_DRAWABLE_BOTTOM;
import static com.android.SdkConstants.ATTR_DRAWABLE_LEFT;
import static com.android.SdkConstants.ATTR_DRAWABLE_RIGHT;
import static com.android.SdkConstants.ATTR_DRAWABLE_TOP;
/**
* 检测是否在 drawableLeft / drawableRight / drawableTop / drawableBottom 中传入了 Vector Drawable,在 4.0 及以下版本的系统中会导致 Crash
* Created by Kayo on 2017/8/29.
*/
public class QMUIXmlVectorDrawableDetector extends ResourceXmlDetector {
public static final Issue ISSUE_XML_VECTOR_DRAWABLE =
Issue.create("QMUIGetVectorDrawableWithWrongProperty",
"Should use the corresponding property to get vector drawable.",
"Using the normal property to get the vector drawable will cause a crash on Android versions below 4.0.",
Category.CORRECTNESS, 8, Severity.ERROR,
new Implementation(QMUIXmlVectorDrawableDetector.class, Scope.RESOURCE_FILE_SCOPE));
private static final Collection<String> mAttrList = Lists.newArrayList(ATTR_DRAWABLE_LEFT, ATTR_DRAWABLE_RIGHT, ATTR_DRAWABLE_TOP, ATTR_DRAWABLE_BOTTOM);
@Override
public boolean appliesTo(ResourceFolderType folderType) {
return ResourceFolderType.LAYOUT == folderType;
}
@Override
public Collection<String> getApplicableElements() {
return ALL;
}
@Override
public Collection<String> getApplicableAttributes() {
return mAttrList;
}
@Override
public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
// 判断资源文件夹是否存在
Project project = context.getProject();
List<File> resourceFolder = project.getResourceFolders();
if (resourceFolder.isEmpty()) {
return;
}
// 获取项目资源文件夹路径
String resourcePath = resourceFolder.get(0).getAbsolutePath();
// 获取 drawable 名字
String drawableName = attribute.getValue().replace("@drawable/", "");
FileInputStream fileInputStream = null;
BufferedReader reader = null;
try {
// 若 drawable 为 Vector Drawable,则文件后缀为 xml,根据 resource 路径,drawable 名字,文件后缀拼接出完整路径
fileInputStream = new FileInputStream(resourcePath + "/drawable/" + drawableName + ".xml");
reader = new BufferedReader(new InputStreamReader(fileInputStream));
String line = reader.readLine();
if (line.contains("vector")) {
// 若文件存在,并且包含首行包含 vector,则为 Vector Drawable,抛出警告
context.report(ISSUE_XML_VECTOR_DRAWABLE, attribute, context.getLocation(attribute), attribute.getValue() + " 为 Vector Drawable,请使用 Vector 属性进行设置,避免 4.0 及以下版本的系统产生 Crash");
}
} catch (Exception ignored) {
}finally {
if(fileInputStream != null){
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(reader != null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
...@@ -92,7 +92,6 @@ public class SettlementActivity extends BaseActivity<SettlementPresenter> implem ...@@ -92,7 +92,6 @@ public class SettlementActivity extends BaseActivity<SettlementPresenter> implem
} }
}); });
mTopBar.setTitle(LanguageUtils.get_language_system(this, "funcSelect.settlement", "清機")).setTextColor(ArmsUtils.getColor(this, R.color.theme_white_color)); mTopBar.setTitle(LanguageUtils.get_language_system(this, "funcSelect.settlement", "清機")).setTextColor(ArmsUtils.getColor(this, R.color.theme_white_color));
;
} }
@OnClick({R2.id.btn_settlement_report}) @OnClick({R2.id.btn_settlement_report})
...@@ -157,8 +156,10 @@ public class SettlementActivity extends BaseActivity<SettlementPresenter> implem ...@@ -157,8 +156,10 @@ public class SettlementActivity extends BaseActivity<SettlementPresenter> implem
@Override @Override
public void returnSettlementData(SettlementReport.DataBean datasBean) { public void returnSettlementData(SettlementReport.DataBean datasBean) {
this.mSettlementReportBean = datasBean; this.mSettlementReportBean = datasBean;
if(mSettlementReportBean.getRestaurantOperation() != null) {
String lastSettlementText = LanguageUtils.get_language_system(this, "", "上次清機時間:"); String lastSettlementText = LanguageUtils.get_language_system(this, "", "上次清機時間:");
setLastTime(lastSettlementText + mSettlementReportBean.getYesterdayTime()); setLastTime(lastSettlementText + TimeUtils.getStringByFormat(mSettlementReportBean.getRestaurantOperation().getOpenTime(), TimeUtils.dateFormatYMDHMS) );
}
} }
......
...@@ -2,7 +2,9 @@ package com.gingersoft.gsa.cloud.main.mvp.ui.activity; ...@@ -2,7 +2,9 @@ package com.gingersoft.gsa.cloud.main.mvp.ui.activity;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils;
import android.view.View; import android.view.View;
import android.widget.Button;
import android.widget.ScrollView; import android.widget.ScrollView;
import android.widget.TextView; import android.widget.TextView;
...@@ -16,9 +18,12 @@ import androidx.recyclerview.widget.RecyclerView; ...@@ -16,9 +18,12 @@ import androidx.recyclerview.widget.RecyclerView;
import com.billy.cc.core.component.CC; import com.billy.cc.core.component.CC;
import com.gingersoft.gsa.cloud.base.application.GsaCloudApplication; import com.gingersoft.gsa.cloud.base.application.GsaCloudApplication;
import com.gingersoft.gsa.cloud.base.utils.JsonUtils;
import com.gingersoft.gsa.cloud.base.utils.LanguageUtils; import com.gingersoft.gsa.cloud.base.utils.LanguageUtils;
import com.gingersoft.gsa.cloud.base.utils.MoneyUtil; import com.gingersoft.gsa.cloud.base.utils.MoneyUtil;
import com.gingersoft.gsa.cloud.base.utils.PrintTransitUtils; import com.gingersoft.gsa.cloud.base.utils.PrintTransitUtils;
import com.gingersoft.gsa.cloud.base.utils.constans.Constans;
import com.gingersoft.gsa.cloud.base.utils.other.SPUtils;
import com.gingersoft.gsa.cloud.base.utils.time.TimeUtil; import com.gingersoft.gsa.cloud.base.utils.time.TimeUtil;
import com.gingersoft.gsa.cloud.base.utils.time.TimeUtils; import com.gingersoft.gsa.cloud.base.utils.time.TimeUtils;
import com.gingersoft.gsa.cloud.main.R; import com.gingersoft.gsa.cloud.main.R;
...@@ -93,12 +98,6 @@ public class SettlementReportActivity extends BaseActivity<SettlementReportPrese ...@@ -93,12 +98,6 @@ public class SettlementReportActivity extends BaseActivity<SettlementReportPrese
protected String dfformat = "#0.00"; protected String dfformat = "#0.00";
protected DecimalFormat df; protected DecimalFormat df;
private SettlementReport.DataBean mSettlementReportBean;
private static SettlementReportActivity settlementReportActivity;
public static SettlementReportActivity getInstance() {
return settlementReportActivity;
}
@Override @Override
public void setupActivityComponent(@NonNull AppComponent appComponent) { public void setupActivityComponent(@NonNull AppComponent appComponent) {
...@@ -122,11 +121,11 @@ public class SettlementReportActivity extends BaseActivity<SettlementReportPrese ...@@ -122,11 +121,11 @@ public class SettlementReportActivity extends BaseActivity<SettlementReportPrese
@Override @Override
public void initIntent() { public void initIntent() {
Intent intent = getIntent(); Intent intent = getIntent();
mSettlementReportBean = (SettlementReport.DataBean) intent.getSerializableExtra("settlementReportBean"); SettlementReport.DataBean settlementReportBean = (SettlementReport.DataBean) intent.getSerializableExtra("settlementReportBean");
df = new DecimalFormat(dfformat); df = new DecimalFormat(dfformat);
if (mSettlementReportBean != null) { if (settlementReportBean != null) {
mPresenter.initAdapter(); mPresenter.initAdapter();
returnSettlementData(mSettlementReportBean); returnSettlementData(settlementReportBean);
} else { } else {
mPresenter.initAdapter(); mPresenter.initAdapter();
mPresenter.getSettlementReport(); mPresenter.getSettlementReport();
...@@ -140,6 +139,20 @@ public class SettlementReportActivity extends BaseActivity<SettlementReportPrese ...@@ -140,6 +139,20 @@ public class SettlementReportActivity extends BaseActivity<SettlementReportPrese
killMyself(); killMyself();
// overridePendingTransition(R.anim.slide_still, R.anim.slide_out_right); // overridePendingTransition(R.anim.slide_still, R.anim.slide_out_right);
}); });
Button rightBtn = mTopBar.addRightTextButton("打印", R.id.tv_right);
rightBtn.setTextColor(ArmsUtils.getColor(this, R.color.theme_white_color));
rightBtn.setOnClickListener(v -> {
String settlementReportJson = (String) SPUtils.get(mContext, Constans.SETTLEMENT_REPORT, "");
if (!TextUtils.isEmpty(settlementReportJson)) {
SettlementReport.DataBean datasBean = JsonUtils.parseObject(settlementReportJson, SettlementReport.DataBean.class);
if(datasBean != null){
returnSettlementData(datasBean);
printRepore();
}
} else {
showMessage("暫無可印報表");
}
});
mTopBar.setTitle(LanguageUtils.get_language_system(this, "function.order.detail2", "清機報表")).setTextColor(ArmsUtils.getColor(this, R.color.theme_white_color)); mTopBar.setTitle(LanguageUtils.get_language_system(this, "function.order.detail2", "清機報表")).setTextColor(ArmsUtils.getColor(this, R.color.theme_white_color));
} }
...@@ -223,6 +236,10 @@ public class SettlementReportActivity extends BaseActivity<SettlementReportPrese ...@@ -223,6 +236,10 @@ public class SettlementReportActivity extends BaseActivity<SettlementReportPrese
@Override @Override
public void returnSettlementData(SettlementReport.DataBean datasBean) { public void returnSettlementData(SettlementReport.DataBean datasBean) {
if (datasBean.getVo() != null && datasBean.getVo().getPrices() > 0) {
//保存下次重印數據
SPUtils.put(mContext, Constans.SETTLEMENT_REPORT, JsonUtils.toJson(datasBean));
}
List<SectionTextItem3> settlementReportItems = new ArrayList<>(); List<SectionTextItem3> settlementReportItems = new ArrayList<>();
List<SectionTextItem5> settlementReportItem5s = new ArrayList<>(); List<SectionTextItem5> settlementReportItem5s = new ArrayList<>();
...@@ -243,29 +260,28 @@ public class SettlementReportActivity extends BaseActivity<SettlementReportPrese ...@@ -243,29 +260,28 @@ public class SettlementReportActivity extends BaseActivity<SettlementReportPrese
String headcountAndAverageConsumptionText = LanguageUtils.get_language_system(this, "headcount.or.average.consumption", "人數/平均消費"); String headcountAndAverageConsumptionText = LanguageUtils.get_language_system(this, "headcount.or.average.consumption", "人數/平均消費");
String billStatusText = LanguageUtils.get_language_system(this, "", "賬單現況"); String billStatusText = LanguageUtils.get_language_system(this, "", "賬單現況");
String outstandingBillText = LanguageUtils.get_language_system(this, "", "未完成賬單"); // String outstandingBillText = LanguageUtils.get_language_system(this, "", "未完成賬單");
String billsReceivedText = LanguageUtils.get_language_system(this, "", "已完成賬單"); // String billsReceivedText = LanguageUtils.get_language_system(this, "", "已完成賬單");
String outstandingBillText = LanguageUtils.get_language_system(this, "", "未完成單");
String billsReceivedText = LanguageUtils.get_language_system(this, "", "已完成單");
String cumulativeTurnoverMonthText = LanguageUtils.get_language_system(this, "", "本月累計營業額"); String cumulativeTurnoverMonthText = LanguageUtils.get_language_system(this, "", "本月累計營業額");
String endReportText = LanguageUtils.get_language_system(this, "", "報表完結"); String endReportText = LanguageUtils.get_language_system(this, "", "報表完結");
String readersText = LanguageUtils.get_language_system(this, "", "讀取人員"); String readersText = LanguageUtils.get_language_system(this, "", "讀取人員");
tv_last_time.setText(lastSettlementText + datasBean.getYesterdayTime());
SettlementReport.DataBean.RestaurantOperationBean restaurantOperationBean = datasBean.getRestaurantOperation(); SettlementReport.DataBean.RestaurantOperationBean restaurantOperationBean = datasBean.getRestaurantOperation();
if (restaurantOperationBean != null) { if (restaurantOperationBean != null) {
String currentDate = TimeUtil.getCurrentDate(TimeUtil.dateFormatYMDHMS);
tv_business_area_title.setText(dailyBusinessReportText); tv_business_area_title.setText(dailyBusinessReportText);
tv_last_time.setText(lastSettlementText + TimeUtils.getStringByFormat(restaurantOperationBean.getOpenTime(), TimeUtils.dateFormatYMDHMS));
tv_start_time.setText(byBusinessDateText + TimeUtils.getStringByFormat(restaurantOperationBean.getOpenTime(), TimeUtils.dateFormatYMDHMS)); tv_start_time.setText(byBusinessDateText + TimeUtils.getStringByFormat(restaurantOperationBean.getOpenTime(), TimeUtils.dateFormatYMDHMS));
// tv_end_time.setText(toBusinessDateText + TimeUtils.getStringByFormat(restaurantOperationBean.getOperationTime(), TimeUtils.dateFormatYMDHMS)); tv_end_time.setText(toBusinessDateText + TimeUtils.getStringByFormat(restaurantOperationBean.getOperationTime(), TimeUtils.dateFormatYMDHMS));
tv_end_time.setText(toBusinessDateText + currentDate);
} }
SettlementReport.DataBean.VoBean voBean = datasBean.getVo(); SettlementReport.DataBean.VoBean voBean = datasBean.getVo();
if (voBean != null) { if (voBean != null) {
settlementReportItem5s.add(new SectionTextItem5(projectTotalSalesText, null, null, null, cashStr + df.format(voBean.getPrices()))); settlementReportItem5s.add(new SectionTextItem5(projectTotalSalesText, null, null, null, cashStr + df.format(voBean.getPrices())));
settlementReportItem5s.add(new SectionTextItem5(netTurnoverText, null, null, null, cashStr+ df.format(voBean.getTotamount()))); settlementReportItem5s.add(new SectionTextItem5(netTurnoverText, null, null, null, cashStr + df.format(voBean.getTotamount())));
// if (voBean.getPayNum() > 0) { // if (voBean.getPayNum() > 0) {
// String creditCardText = LanguageUtils.get_language_system(this, "credit.card", "信用卡"); // String creditCardText = LanguageUtils.get_language_system(this, "credit.card", "信用卡");
// SectionTextItem5 printItem = new SectionTextItem5(creditCardText, String.valueOf(voBean.getPayNum()), null,null,"$" + df.format(voBean.getPayamount())); // SectionTextItem5 printItem = new SectionTextItem5(creditCardText, String.valueOf(voBean.getPayNum()), null,null,"$" + df.format(voBean.getPayamount()));
...@@ -368,7 +384,7 @@ public class SettlementReportActivity extends BaseActivity<SettlementReportPrese ...@@ -368,7 +384,7 @@ public class SettlementReportActivity extends BaseActivity<SettlementReportPrese
//已收款帳單 //已收款帳單
if (analysisBeanMap.containsKey(billsReceivedText)) { if (analysisBeanMap.containsKey(billsReceivedText)) {
SettlementReport.DataBean.AnalysisBean analysisBean = analysisBeanMap.get(billsReceivedText); SettlementReport.DataBean.AnalysisBean analysisBean = analysisBeanMap.get(billsReceivedText);
settlementReportItem5s.add(new SectionTextItem5(analysisBean.getTypeName(), String.valueOf(analysisBean.getNum()), String.valueOf(analysisBean.getPerson()), null,cashStr + df.format(analysisBean.getAmount()))); settlementReportItem5s.add(new SectionTextItem5(analysisBean.getTypeName(), String.valueOf(analysisBean.getNum()), String.valueOf(analysisBean.getPerson()), null, cashStr + df.format(analysisBean.getAmount())));
item5Amount += analysisBean.getAmount(); item5Amount += analysisBean.getAmount();
item5num += analysisBean.getNum(); item5num += analysisBean.getNum();
item5PeopleNum += analysisBean.getPerson(); item5PeopleNum += analysisBean.getPerson();
......
...@@ -86,12 +86,10 @@ public class TableBean { ...@@ -86,12 +86,10 @@ public class TableBean {
private int serviceCharge; private int serviceCharge;
private int memberId; private int memberId;
/** /**
* 可使用 0 * 未開檯 0
* 操作中 1 * 已開檯 1
* 已开台 2 * 已送單 2
* 已印单 3 * 已印单 3
* 已结账 4
* 连台 6
*/ */
private int status; private int status;
/** /**
...@@ -99,7 +97,9 @@ public class TableBean { ...@@ -99,7 +97,9 @@ public class TableBean {
*/ */
private int person; private int person;
/** /**
* 使用狀態 * 使用狀態:
* 未使用 0
* 已使用 1
*/ */
private int useStatus; private int useStatus;
/** /**
......
...@@ -11,5 +11,5 @@ public class Constans { ...@@ -11,5 +11,5 @@ public class Constans {
public final static String IP_PRINT = "ip_print"; public final static String IP_PRINT = "ip_print";
public final static String SETTLEMENT_REPORT = "settlement_report";
} }
package com.gingersoft.gsa.cloud.ui.widget.dialog;
import android.app.Activity;
import com.gingersoft.gsa.cloud.base.R;
import com.qmuiteam.qmui.widget.dialog.QMUIDialog;
import com.qmuiteam.qmui.widget.dialog.QMUIDialogAction;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 作者:ELEGANT_BIN
* 版本:1.6.0
* 创建日期:2020-04-03
* 修订历史:2020-04-03
* 描述:常用提示Dialog
*/
public class CommonTipDialog {
/**
* 提示確認dialog 確認后且執行對應方法
* @param context
* @param msg
* @param c
* @param object
* @param methodName
* @param parameterTypes
* @param parameters
*/
public static void showTipAndExecuteMethodDialog(Activity context,String msg, Class c, Object object, String methodName, Class[] parameterTypes, Object[] parameters) {
QMUIDialog.MessageDialogBuilder dialogBuilder = new QMUIDialog.MessageDialogBuilder(context);
dialogBuilder.setTitle("溫馨提示");
dialogBuilder.setMessage(msg);
dialogBuilder.addAction("取消", (dialog, index) -> dialog.dismiss());
dialogBuilder.addAction(0, "確認", QMUIDialogAction.ACTION_PROP_NEGATIVE, (dialog, index) -> {
dialog.dismiss();
try {
Method method = c.getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
method.invoke(object, parameters);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
});
dialogBuilder.create(R.style.MyDialogTheme2).show();
}
public static void showTipDialog(Activity context, String msg) {
QMUIDialog.MessageDialogBuilder dialogBuilder = new QMUIDialog.MessageDialogBuilder(context);
dialogBuilder.setTitle("溫馨提示");
dialogBuilder.setMessage(msg);
dialogBuilder.addAction("確定", (dialog, index) -> dialog.dismiss());
dialogBuilder.create(R.style.MyDialogTheme2).show();
}
}
/*.bin
/*.iml
/.DS_Store
/.gradletasknamecache
/.idea
/bin
/build
/local.properties
ext.alwaysLib = true //虽然apply了cc-settings-2.gradle,但一直作为library编译,否则别的组件依赖此module时会报错
apply from: rootProject.file("cc-settings.gradle")
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
//version = QMUI_VERSION
//noinspection GroovyMissingReturnStatement
android {
compileSdkVersion rootProject.ext.android["compileSdkVersion"]
defaultConfig {
minSdkVersion rootProject.ext.android["minSdkVersion"]
targetSdkVersion rootProject.ext.android["targetSdkVersion"]
versionCode rootProject.ext.android["versionCode"]
versionName rootProject.ext.android["versionName"]
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
multiDexEnabled true
}
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
debug {
buildConfigField "boolean", "LOG_DEBUG", "true"
buildConfigField "boolean", "USE_CANARY", "true"
minifyEnabled false
proguardFiles 'proguard-rules.pro'
}
release {
buildConfigField "boolean", "LOG_DEBUG", "false"
buildConfigField "boolean", "USE_CANARY", "false"
minifyEnabled false
zipAlignEnabled false
proguardFiles 'proguard-rules.pro'
}
}
// libraryVariants.all{ variant ->
// variant.mergeResources.doLast {
// replaceTheme variant
// }
// }
// testVariants.all { variant ->
// variant.mergeResources.doLast {
// replaceTheme variant
// }
// }
}
//def replaceTheme(variant){
// println "dirName::${variant.dirName}"
// def output = "AppConfigTheme"
//
// File valuesFile = file("${buildDir}/intermediates/res/merged/${variant.dirName}/values/values.xml")
// String content = valuesFile.getText('UTF-8')
// content = content.replaceAll(/\$\{QMUI_PARENT_THEME\}/, output)
// valuesFile.write(content, 'UTF-8')
//}
dependencies {
api rootProject.ext.dependencies["appcompat-v7"]
api rootProject.ext.dependencies["annotations"]
api rootProject.ext.dependencies["design"]
api rootProject.ext.dependencies["constraintlayout"]
lintChecks project(':lintrule')
//test
testImplementation 'junit:junit:4.12'
api 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
// compileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
// deploy
File deployConfig = rootProject.file('gradle/deploy.properties')
if (deployConfig.exists()) {
apply from: rootProject.file('gradle/deploy.gradle')
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied. See the License for the specific language governing permissions and
limitations under the License.
-->
<lint>
<!-- Disable the given check in this project -->
<issue id="HardcodedText" severity="ignore"/>
<issue id="SmallSp" severity="ignore"/>
<issue id="IconMissingDensityFolder" severity="ignore"/>
<issue id="RtlHardcoded" severity="ignore"/>
<issue id="Deprecated" severity="warning">
<ignore regexp="singleLine"/>
</issue>
<issue id="RtlSymmetry" severity="ignore"/>
</lint>
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/chant/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.qmuiteam.qmui">
</manifest>
(function(){
var doc = document;
if(window.QMUIBridge){
return;
}
var messagingIframe = createIframe(doc);
var sendingMessageQueue = [];
var receivedMessageQueue = [];
var messageHandlers = {};
var QUEUE_HAS_MESSAGE = 'qmui://__QUEUE_MESSAGE__/';
var responseCallbacks = {};
var uuid = 1;
function createIframe(doc) {
var iframe = doc.createElement('iframe');
iframe.style.display = 'none';
doc.documentElement.appendChild(iframe);
return iframe;
}
function send(data, callback) {
if(!data){
throw new Error("message == null")
}
var message = {
data: data
}
if(callback){
var callbackId = 'cb_' + (uuid++) + '_' + (new Date() - 0);
responseCallbacks[callbackId] = callback;
message.callbackId = callbackId;
}
sendingMessageQueue.push(message);
messagingIframe.src = QUEUE_HAS_MESSAGE;
}
function _fetchQueueFromNative(){
var messageQueueString = JSON.stringify(sendingMessageQueue);
sendingMessageQueue = [];
return messageQueueString;
}
function _handleResponseFromNative(responseStr){
var response = JSON.parse(responseStr);
if(response.id){
var responseCallback = responseCallbacks[response.id];
if(responseCallback){
responseCallback(response.data);
delete responseCallbacks[response.id];
}
}
}
var QMUIBridge = window.QMUIBridge = {
send: send,
_fetchQueueFromNative: _fetchQueueFromNative,
_handleResponseFromNative: _handleResponseFromNative
};
var readyEvent = doc.createEvent('Events');
readyEvent.initEvent('QMUIBridgeReady');
readyEvent.bridge = QMUIBridge;
doc.dispatchEvent(readyEvent);
})()
\ No newline at end of file
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui;
import androidx.interpolator.view.animation.FastOutLinearInInterpolator;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
/**
* @author cginechen
* @date 2017-09-02
*/
public class QMUIInterpolatorStaticHolder {
public static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
public static final Interpolator FAST_OUT_SLOW_IN_INTERPOLATOR = new FastOutSlowInInterpolator();
public static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR = new FastOutLinearInInterpolator();
public static final Interpolator LINEAR_OUT_SLOW_IN_INTERPOLATOR = new LinearOutSlowInInterpolator();
public static final Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();
public static final Interpolator ACCELERATE_INTERPOLATOR = new AccelerateInterpolator();
public static final Interpolator ACCELERATE_DECELERATE_INTERPOLATOR = new AccelerateDecelerateInterpolator();
public static final Interpolator QUNITIC_INTERPOLATOR = new Interpolator() {
@Override
public float getInterpolation(float t) {
t -= 1.0f;
return t * t * t * t * t + 1.0f;
}
};
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui;
/**
*
* @author cginechen
* @date 2016-08-11
*/
public class QMUILog {
public interface QMUILogDelegate {
void e(final String tag, final String msg, final Object ... obj);
void w(final String tag, final String msg, final Object ... obj);
void i(final String tag, final String msg, final Object ... obj);
void d(final String tag, final String msg, final Object ... obj);
void printErrStackTrace(String tag, Throwable tr, final String format, final Object ... obj);
}
private static QMUILogDelegate sDelegete = null;
public static void setDelegete(QMUILogDelegate delegete) {
sDelegete = delegete;
}
public static void e(final String tag, final String msg, final Object ... obj) {
if (sDelegete != null) {
sDelegete.e(tag, msg, obj);
}
}
public static void w(final String tag, final String msg, final Object ... obj) {
if (sDelegete != null) {
sDelegete.w(tag, msg, obj);
}
}
public static void i(final String tag, final String msg, final Object ... obj) {
if (sDelegete != null) {
sDelegete.i(tag, msg, obj);
}
}
public static void d(final String tag, final String msg, final Object ... obj) {
if (sDelegete != null) {
sDelegete.d(tag, msg, obj);
}
}
public static void printErrStackTrace(String tag, Throwable tr, final String format, final Object ... obj) {
if (sDelegete != null) {
sDelegete.printErrStackTrace(tag, tr, format, obj);
}
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.alpha;
import android.content.Context;
import androidx.appcompat.widget.AppCompatButton;
import android.util.AttributeSet;
/**
* 在 pressed 和 disabled 时改变 View 的透明度
*/
public class QMUIAlphaButton extends AppCompatButton implements QMUIAlphaViewInf {
private QMUIAlphaViewHelper mAlphaViewHelper;
public QMUIAlphaButton(Context context) {
super(context);
}
public QMUIAlphaButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public QMUIAlphaButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private QMUIAlphaViewHelper getAlphaViewHelper() {
if (mAlphaViewHelper == null) {
mAlphaViewHelper = new QMUIAlphaViewHelper(this);
}
return mAlphaViewHelper;
}
@Override
public void setPressed(boolean pressed) {
super.setPressed(pressed);
getAlphaViewHelper().onPressedChanged(this, pressed);
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
getAlphaViewHelper().onEnabledChanged(this, enabled);
}
/**
* 设置是否要在 press 时改变透明度
*
* @param changeAlphaWhenPress 是否要在 press 时改变透明度
*/
@Override
public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
getAlphaViewHelper().setChangeAlphaWhenPress(changeAlphaWhenPress);
}
/**
* 设置是否要在 disabled 时改变透明度
*
* @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
*/
@Override
public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
getAlphaViewHelper().setChangeAlphaWhenDisable(changeAlphaWhenDisable);
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.alpha;
import android.content.Context;
import android.util.AttributeSet;
import androidx.constraintlayout.widget.ConstraintLayout;
/**
* 在 pressed 和 disabled 时改变 View 的透明度
*/
public class QMUIAlphaConstraintLayout extends ConstraintLayout implements QMUIAlphaViewInf {
private QMUIAlphaViewHelper mAlphaViewHelper;
public QMUIAlphaConstraintLayout(Context context) {
super(context);
}
public QMUIAlphaConstraintLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public QMUIAlphaConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private QMUIAlphaViewHelper getAlphaViewHelper() {
if (mAlphaViewHelper == null) {
mAlphaViewHelper = new QMUIAlphaViewHelper(this);
}
return mAlphaViewHelper;
}
@Override
public void setPressed(boolean pressed) {
super.setPressed(pressed);
getAlphaViewHelper().onPressedChanged(this, pressed);
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
getAlphaViewHelper().onEnabledChanged(this, enabled);
}
/**
* 设置是否要在 press 时改变透明度
*
* @param changeAlphaWhenPress 是否要在 press 时改变透明度
*/
@Override
public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
getAlphaViewHelper().setChangeAlphaWhenPress(changeAlphaWhenPress);
}
/**
* 设置是否要在 disabled 时改变透明度
*
* @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
*/
@Override
public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
getAlphaViewHelper().setChangeAlphaWhenDisable(changeAlphaWhenDisable);
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.alpha;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;
/**
* 在 pressed 和 disabled 时改变 View 的透明度
*/
public class QMUIAlphaFrameLayout extends FrameLayout implements QMUIAlphaViewInf {
private QMUIAlphaViewHelper mAlphaViewHelper;
public QMUIAlphaFrameLayout(Context context) {
super(context);
}
public QMUIAlphaFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public QMUIAlphaFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private QMUIAlphaViewHelper getAlphaViewHelper() {
if (mAlphaViewHelper == null) {
mAlphaViewHelper = new QMUIAlphaViewHelper(this);
}
return mAlphaViewHelper;
}
@Override
public void setPressed(boolean pressed) {
super.setPressed(pressed);
getAlphaViewHelper().onPressedChanged(this, pressed);
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
getAlphaViewHelper().onEnabledChanged(this, enabled);
}
/**
* 设置是否要在 press 时改变透明度
*
* @param changeAlphaWhenPress 是否要在 press 时改变透明度
*/
@Override
public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
getAlphaViewHelper().setChangeAlphaWhenPress(changeAlphaWhenPress);
}
/**
* 设置是否要在 disabled 时改变透明度
*
* @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
*/
@Override
public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
getAlphaViewHelper().setChangeAlphaWhenDisable(changeAlphaWhenDisable);
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.alpha;
import android.content.Context;
import androidx.appcompat.widget.AppCompatImageButton;
import android.util.AttributeSet;
public class QMUIAlphaImageButton extends AppCompatImageButton implements QMUIAlphaViewInf {
private QMUIAlphaViewHelper mAlphaViewHelper;
public QMUIAlphaImageButton(Context context) {
super(context);
}
public QMUIAlphaImageButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public QMUIAlphaImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private QMUIAlphaViewHelper getAlphaViewHelper() {
if (mAlphaViewHelper == null) {
mAlphaViewHelper = new QMUIAlphaViewHelper(this);
}
return mAlphaViewHelper;
}
@Override
public void setPressed(boolean pressed) {
super.setPressed(pressed);
getAlphaViewHelper().onPressedChanged(this, pressed);
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
getAlphaViewHelper().onEnabledChanged(this, enabled);
}
/**
* 设置是否要在 press 时改变透明度
*
* @param changeAlphaWhenPress 是否要在 press 时改变透明度
*/
@Override
public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
getAlphaViewHelper().setChangeAlphaWhenPress(changeAlphaWhenPress);
}
/**
* 设置是否要在 disabled 时改变透明度
*
* @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
*/
@Override
public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
getAlphaViewHelper().setChangeAlphaWhenDisable(changeAlphaWhenDisable);
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.alpha;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
/**
* 在 pressed 和 disabled 时改变 View 的透明度
*/
public class QMUIAlphaLinearLayout extends LinearLayout implements QMUIAlphaViewInf {
private QMUIAlphaViewHelper mAlphaViewHelper;
public QMUIAlphaLinearLayout(Context context) {
super(context);
}
public QMUIAlphaLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public QMUIAlphaLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private QMUIAlphaViewHelper getAlphaViewHelper() {
if (mAlphaViewHelper == null) {
mAlphaViewHelper = new QMUIAlphaViewHelper(this);
}
return mAlphaViewHelper;
}
@Override
public void setPressed(boolean pressed) {
super.setPressed(pressed);
getAlphaViewHelper().onPressedChanged(this, pressed);
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
getAlphaViewHelper().onEnabledChanged(this, enabled);
}
/**
* 设置是否要在 press 时改变透明度
*
* @param changeAlphaWhenPress 是否要在 press 时改变透明度
*/
@Override
public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
getAlphaViewHelper().setChangeAlphaWhenPress(changeAlphaWhenPress);
}
/**
* 设置是否要在 disabled 时改变透明度
*
* @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
*/
@Override
public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
getAlphaViewHelper().setChangeAlphaWhenDisable(changeAlphaWhenDisable);
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.alpha;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
/**
* 在 pressed 和 disabled 时改变 View 的透明度
*/
public class QMUIAlphaRelativeLayout extends RelativeLayout implements QMUIAlphaViewInf {
private QMUIAlphaViewHelper mAlphaViewHelper;
public QMUIAlphaRelativeLayout(Context context) {
super(context);
}
public QMUIAlphaRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public QMUIAlphaRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private QMUIAlphaViewHelper getAlphaViewHelper() {
if (mAlphaViewHelper == null) {
mAlphaViewHelper = new QMUIAlphaViewHelper(this);
}
return mAlphaViewHelper;
}
@Override
public void setPressed(boolean pressed) {
super.setPressed(pressed);
getAlphaViewHelper().onPressedChanged(this, pressed);
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
getAlphaViewHelper().onEnabledChanged(this, enabled);
}
/**
* 设置是否要在 press 时改变透明度
*
* @param changeAlphaWhenPress 是否要在 press 时改变透明度
*/
@Override
public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
getAlphaViewHelper().setChangeAlphaWhenPress(changeAlphaWhenPress);
}
/**
* 设置是否要在 disabled 时改变透明度
*
* @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
*/
@Override
public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
getAlphaViewHelper().setChangeAlphaWhenDisable(changeAlphaWhenDisable);
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.alpha;
import android.content.Context;
import android.util.AttributeSet;
import com.qmuiteam.qmui.widget.textview.QMUISpanTouchFixTextView;
/**
* 在 pressed 和 disabled 时改变 View 的透明度
*/
public class QMUIAlphaTextView extends QMUISpanTouchFixTextView implements QMUIAlphaViewInf {
private QMUIAlphaViewHelper mAlphaViewHelper;
public QMUIAlphaTextView(Context context) {
super(context);
}
public QMUIAlphaTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public QMUIAlphaTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private QMUIAlphaViewHelper getAlphaViewHelper() {
if (mAlphaViewHelper == null) {
mAlphaViewHelper = new QMUIAlphaViewHelper(this);
}
return mAlphaViewHelper;
}
@Override
protected void onSetPressed(boolean pressed) {
super.onSetPressed(pressed);
getAlphaViewHelper().onPressedChanged(this, pressed);
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
getAlphaViewHelper().onEnabledChanged(this, enabled);
}
/**
* 设置是否要在 press 时改变透明度
*
* @param changeAlphaWhenPress 是否要在 press 时改变透明度
*/
@Override
public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
getAlphaViewHelper().setChangeAlphaWhenPress(changeAlphaWhenPress);
}
/**
* 设置是否要在 disabled 时改变透明度
*
* @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
*/
@Override
public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
getAlphaViewHelper().setChangeAlphaWhenDisable(changeAlphaWhenDisable);
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.alpha;
import androidx.annotation.NonNull;
import android.view.View;
import com.qmuiteam.qmui.R;
import com.qmuiteam.qmui.util.QMUIResHelper;
import java.lang.ref.WeakReference;
public class QMUIAlphaViewHelper {
private WeakReference<View> mTarget;
/**
* 设置是否要在 press 时改变透明度
*/
private boolean mChangeAlphaWhenPress = true;
/**
* 设置是否要在 disabled 时改变透明度
*/
private boolean mChangeAlphaWhenDisable = true;
private float mNormalAlpha = 1f;
private float mPressedAlpha = .5f;
private float mDisabledAlpha = .5f;
public QMUIAlphaViewHelper(@NonNull View target) {
mTarget = new WeakReference<>(target);
mPressedAlpha = QMUIResHelper.getAttrFloatValue(target.getContext(), R.attr.qmui_alpha_pressed);
mDisabledAlpha = QMUIResHelper.getAttrFloatValue(target.getContext(), R.attr.qmui_alpha_disabled);
}
public QMUIAlphaViewHelper(@NonNull View target, float pressedAlpha, float disabledAlpha) {
mTarget = new WeakReference<>(target);
mPressedAlpha = pressedAlpha;
mDisabledAlpha = disabledAlpha;
}
/**
* 在 {@link View#setPressed(boolean)} 中调用,通知 helper 更新
* @param current the view to be handled, maybe not equal to target view
* @param pressed {@link View#setPressed(boolean)} 中接收到的参数
*/
public void onPressedChanged(View current, boolean pressed) {
View target = mTarget.get();
if (target == null) {
return;
}
if (current.isEnabled()) {
target.setAlpha(mChangeAlphaWhenPress && pressed && current.isClickable() ? mPressedAlpha : mNormalAlpha);
} else {
if (mChangeAlphaWhenDisable) {
target.setAlpha(mDisabledAlpha);
}
}
}
/**
* 在 {@link View#setEnabled(boolean)} 中调用,通知 helper 更新
* @param current the view to be handled, maybe not equal to target view
* @param enabled {@link View#setEnabled(boolean)} 中接收到的参数
*/
public void onEnabledChanged(View current, boolean enabled) {
View target = mTarget.get();
if (target == null) {
return;
}
float alphaForIsEnable;
if (mChangeAlphaWhenDisable) {
alphaForIsEnable = enabled ? mNormalAlpha : mDisabledAlpha;
} else {
alphaForIsEnable = mNormalAlpha;
}
if (current != target && target.isEnabled() != enabled) {
target.setEnabled(enabled);
}
target.setAlpha(alphaForIsEnable);
}
/**
* 设置是否要在 press 时改变透明度
*
* @param changeAlphaWhenPress 是否要在 press 时改变透明度
*/
public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
mChangeAlphaWhenPress = changeAlphaWhenPress;
}
/**
* 设置是否要在 disabled 时改变透明度
*
* @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
*/
public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
mChangeAlphaWhenDisable = changeAlphaWhenDisable;
View target = mTarget.get();
if (target != null) {
onEnabledChanged(target, target.isEnabled());
}
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.alpha;
/**
* 在 pressed 和 disabled 时改变 View 的透明度的接口
*/
public interface QMUIAlphaViewInf {
/**
* 设置是否要在 press 时改变透明度
*
* @param changeAlphaWhenPress 是否要在 press 时改变透明度
*/
void setChangeAlphaWhenPress(boolean changeAlphaWhenPress);
/**
* 设置是否要在 disabled 时改变透明度
*
* @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
*/
void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable);
}
package com.qmuiteam.qmui.kotlin
import android.content.Context
import android.view.View
import androidx.annotation.DimenRes
import androidx.fragment.app.Fragment
fun Context.dip(value: Int): Int = (value * resources.displayMetrics.density).toInt()
fun Context.dip(value: Float): Int = (value * resources.displayMetrics.density).toInt()
fun Context.sp(value: Int): Int = (value * resources.displayMetrics.scaledDensity).toInt()
fun Context.sp(value: Float): Int = (value * resources.displayMetrics.scaledDensity).toInt()
fun Context.px2dp(px: Int): Float = px.toFloat() / resources.displayMetrics.density
fun Context.px2sp(px: Int): Float = px.toFloat() / resources.displayMetrics.scaledDensity
fun Context.dimen(@DimenRes resource: Int): Int = resources.getDimensionPixelSize(resource)
fun View.dip(value: Int): Int = context.dip(value)
fun View.dip(value: Float): Int = context.dip(value)
fun View.sp(value: Int): Int = context.sp(value)
fun View.sp(value: Float): Int = context.sp(value)
fun View.px2dp(px: Int): Float = context.px2dp(px)
fun View.px2sp(px: Int): Float = context.px2sp(px)
fun View.dimen(@DimenRes resource: Int): Int = context.dimen(resource)
// must be called after attached.
fun Fragment.dip(value: Int): Int = context!!.dip(value)
fun Fragment.dip(value: Float): Int = context!!.dip(value)
fun Fragment.sp(value: Int): Int = context!!.sp(value)
fun Fragment.sp(value: Float): Int = context!!.sp(value)
fun Fragment.px2dp(px: Int): Float = context!!.px2dp(px)
fun Fragment.px2sp(px: Int): Float = context!!.px2sp(px)
fun Fragment.dimen(@DimenRes resource: Int): Int = context!!.dimen(resource)
\ No newline at end of file
package com.qmuiteam.qmui.kotlin
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
val matchParent: Int = ViewGroup.LayoutParams.MATCH_PARENT
val wrapContent: Int = ViewGroup.LayoutParams.WRAP_CONTENT
val matchConstraint: Int = ConstraintLayout.LayoutParams.MATCH_CONSTRAINT
val constraintParentId = ConstraintLayout.LayoutParams.PARENT_ID
fun ConstraintLayout.LayoutParams.alignParent4(){
leftToLeft = constraintParentId
rightToRight = constraintParentId
topToTop = constraintParentId
bottomToBottom = constraintParentId
}
fun ConstraintLayout.LayoutParams.alignParentHor(){
leftToLeft = constraintParentId
rightToRight = constraintParentId
}
fun ConstraintLayout.LayoutParams.alignParentVer(){
topToTop = constraintParentId
bottomToBottom = constraintParentId
}
fun ConstraintLayout.LayoutParams.alignParentLeftTop(){
topToTop = constraintParentId
leftToLeft = constraintParentId
}
fun ConstraintLayout.LayoutParams.alignParentLeftBottom(){
bottomToBottom = constraintParentId
leftToLeft = constraintParentId
}
fun ConstraintLayout.LayoutParams.alignParentRightTop(){
topToTop = constraintParentId
rightToRight = constraintParentId
}
fun ConstraintLayout.LayoutParams.alignParentRightBottom(){
bottomToBottom = constraintParentId
rightToRight = constraintParentId
}
fun ConstraintLayout.LayoutParams.alignView4(id: Int){
leftToLeft = id
rightToRight = id
topToTop = id
bottomToBottom = id
}
fun ConstraintLayout.LayoutParams.alignViewHor(id: Int){
leftToLeft = id
rightToRight = id
}
fun ConstraintLayout.LayoutParams.alignViewVer(id: Int){
topToTop = id
bottomToBottom = id
}
fun ConstraintLayout.LayoutParams.alignViewLeftTop(id: Int){
topToTop = id
leftToLeft = id
}
fun ConstraintLayout.LayoutParams.alignViewLeftBottom(id: Int){
bottomToBottom = id
leftToLeft = id
}
fun ConstraintLayout.LayoutParams.alignViewRightTop(id: Int){
topToTop = id
rightToRight = id
}
fun ConstraintLayout.LayoutParams.alignViewRightBottom(id: Int){
bottomToBottom = id
rightToRight = id
}
\ No newline at end of file
package com.qmuiteam.qmui.kotlin
import android.view.View
import com.qmuiteam.qmui.R
import com.qmuiteam.qmui.skin.QMUISkinHelper
import com.qmuiteam.qmui.skin.QMUISkinValueBuilder
fun throttleClick(wait: Long = 200, block: ((View) -> Unit)): View.OnClickListener {
return View.OnClickListener { v ->
val current = System.currentTimeMillis()
val lastClickTime = (v.getTag(R.id.qmui_click_timestamp) as? Long) ?: 0
if (current - lastClickTime > wait) {
v.setTag(R.id.qmui_click_timestamp, current)
block(v)
}
}
}
fun debounceClick(wait: Long = 200, block: ((View) -> Unit)): View.OnClickListener {
return View.OnClickListener { v ->
var action = (v.getTag(R.id.qmui_click_debounce_action) as? DebounceAction)
if(action == null){
action = DebounceAction(v, block)
v.setTag(R.id.qmui_click_debounce_action, action)
}else{
action.block = block
}
v.removeCallbacks(action)
v.postDelayed(action, wait)
}
}
class DebounceAction(val view: View, var block: ((View) -> Unit)): Runnable {
override fun run() {
if(view.isAttachedToWindow){
block(view)
}
}
}
fun View.onClick(wait: Long = 200, block: ((View) -> Unit)) {
setOnClickListener(throttleClick(wait, block))
}
fun View.onDebounceClick(wait: Long = 200, block: ((View) -> Unit)) {
setOnClickListener(debounceClick(wait, block))
}
fun View.skin(block:(QMUISkinValueBuilder.() -> Unit)){
val builder = QMUISkinValueBuilder.acquire();
builder.block()
QMUISkinHelper.setSkinValue(this, builder)
builder.release()
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.layout;
import android.view.View;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;
/**
* Created by cgspine on 2018/3/23.
*/
public interface IQMUILayout {
int HIDE_RADIUS_SIDE_NONE = 0;
int HIDE_RADIUS_SIDE_TOP = 1;
int HIDE_RADIUS_SIDE_RIGHT = 2;
int HIDE_RADIUS_SIDE_BOTTOM = 3;
int HIDE_RADIUS_SIDE_LEFT = 4;
@IntDef(value = {
HIDE_RADIUS_SIDE_NONE,
HIDE_RADIUS_SIDE_TOP,
HIDE_RADIUS_SIDE_RIGHT,
HIDE_RADIUS_SIDE_BOTTOM,
HIDE_RADIUS_SIDE_LEFT})
@Retention(RetentionPolicy.SOURCE)
@interface HideRadiusSide {
}
/**
* limit the width of a layout
*
* @param widthLimit
* @return
*/
boolean setWidthLimit(int widthLimit);
/**
* limit the height of a layout
*
* @param heightLimit
* @return
*/
boolean setHeightLimit(int heightLimit);
/**
* use the shadow elevation from the theme
*/
void setUseThemeGeneralShadowElevation();
/**
* determine if the outline contain the padding area, usually false
*
* @param outlineExcludePadding
*/
void setOutlineExcludePadding(boolean outlineExcludePadding);
/**
* See {@link android.view.View#setElevation(float)}
*
* @param elevation
*/
void setShadowElevation(int elevation);
/**
* See {@link View#getElevation()}
*
* @return
*/
int getShadowElevation();
/**
* set the outline alpha, which will change the shadow
*
* @param shadowAlpha
*/
void setShadowAlpha(float shadowAlpha);
/**
* get the outline alpha we set
*
* @return
*/
float getShadowAlpha();
/**
* @param shadowColor opaque color
* @return
*/
void setShadowColor(int shadowColor);
/**
* @return opaque color
*/
int getShadowColor();
/**
* set the layout radius
*
* @param radius
*/
void setRadius(int radius);
/**
* set the layout radius with one or none side been hidden
*
* @param radius
* @param hideRadiusSide
*/
void setRadius(int radius, @QMUILayoutHelper.HideRadiusSide int hideRadiusSide);
/**
* get the layout radius
*
* @return
*/
int getRadius();
/**
* inset the outline if needed
*
* @param left
* @param top
* @param right
* @param bottom
*/
void setOutlineInset(int left, int top, int right, int bottom);
/**
* the shadow elevation only work after L, so we provide a downgrading compatible solutions for android 4.x
* usually we use border, but the border may be redundant for android L+. so will not show border default,
* if your designer like the border exists with shadow, you can call setShowBorderOnlyBeforeL(false)
*
* @param showBorderOnlyBeforeL
*/
void setShowBorderOnlyBeforeL(boolean showBorderOnlyBeforeL);
/**
* in some case, we maybe hope the layout only have radius in one side.
* but there is no convenient way to write the code like canvas.drawPath,
* so we take another way that hide one radius side
*
* @param hideRadiusSide
*/
void setHideRadiusSide(@HideRadiusSide int hideRadiusSide);
/**
* get the side that we have hidden the radius
*
* @return
*/
int getHideRadiusSide();
/**
* this method will determine the radius and shadow.
*
* @param radius
* @param shadowElevation
* @param shadowAlpha
*/
void setRadiusAndShadow(int radius, int shadowElevation, float shadowAlpha);
/**
* this method will determine the radius and shadow with one or none side be hidden
*
* @param radius
* @param hideRadiusSide
* @param shadowElevation
* @param shadowAlpha
*/
void setRadiusAndShadow(int radius, @HideRadiusSide int hideRadiusSide, int shadowElevation, float shadowAlpha);
/**
* this method will determine the radius and shadow (support shadowColor if after android 9)with one or none side be hidden
*
* @param radius
* @param hideRadiusSide
* @param shadowElevation
* @param shadowColor
* @param shadowAlpha
*/
void setRadiusAndShadow(int radius, @HideRadiusSide int hideRadiusSide, int shadowElevation, int shadowColor, float shadowAlpha);
/**
* border color, if you don not set it, the layout will not draw the border
*
* @param borderColor
*/
void setBorderColor(@ColorInt int borderColor);
/**
* border width, default is 1px, usually no need to set
*
* @param borderWidth
*/
void setBorderWidth(int borderWidth);
/**
* config the top divider
*
* @param topInsetLeft
* @param topInsetRight
* @param topDividerHeight
* @param topDividerColor
*/
void updateTopDivider(int topInsetLeft, int topInsetRight, int topDividerHeight, int topDividerColor);
/**
* config the bottom divider
*
* @param bottomInsetLeft
* @param bottomInsetRight
* @param bottomDividerHeight
* @param bottomDividerColor
*/
void updateBottomDivider(int bottomInsetLeft, int bottomInsetRight, int bottomDividerHeight, int bottomDividerColor);
/**
* config the left divider
*
* @param leftInsetTop
* @param leftInsetBottom
* @param leftDividerWidth
* @param leftDividerColor
*/
void updateLeftDivider(int leftInsetTop, int leftInsetBottom, int leftDividerWidth, int leftDividerColor);
/**
* config the right divider
*
* @param rightInsetTop
* @param rightInsetBottom
* @param rightDividerWidth
* @param rightDividerColor
*/
void updateRightDivider(int rightInsetTop, int rightInsetBottom, int rightDividerWidth, int rightDividerColor);
/**
* show top divider, and hide others
*
* @param topInsetLeft
* @param topInsetRight
* @param topDividerHeight
* @param topDividerColor
*/
void onlyShowTopDivider(int topInsetLeft, int topInsetRight, int topDividerHeight, int topDividerColor);
/**
* show bottom divider, and hide others
*
* @param bottomInsetLeft
* @param bottomInsetRight
* @param bottomDividerHeight
* @param bottomDividerColor
*/
void onlyShowBottomDivider(int bottomInsetLeft, int bottomInsetRight, int bottomDividerHeight, int bottomDividerColor);
/**
* show left divider, and hide others
*
* @param leftInsetTop
* @param leftInsetBottom
* @param leftDividerWidth
* @param leftDividerColor
*/
void onlyShowLeftDivider(int leftInsetTop, int leftInsetBottom, int leftDividerWidth, int leftDividerColor);
/**
* show right divider, and hide others
*
* @param rightInsetTop
* @param rightInsetBottom
* @param rightDividerWidth
* @param rightDividerColor
*/
void onlyShowRightDivider(int rightInsetTop, int rightInsetBottom, int rightDividerWidth, int rightDividerColor);
/**
* after config the border, sometimes we need change the alpha of divider with animation,
* so we provide a method to individually change the alpha
*
* @param dividerAlpha [0, 255]
*/
void setTopDividerAlpha(int dividerAlpha);
/**
* @param dividerAlpha [0, 255]
*/
void setBottomDividerAlpha(int dividerAlpha);
/**
* @param dividerAlpha [0, 255]
*/
void setLeftDividerAlpha(int dividerAlpha);
/**
* @param dividerAlpha [0, 255]
*/
void setRightDividerAlpha(int dividerAlpha);
/**
* only available before android L
*
* @param color
*/
void setOuterNormalColor(int color);
/**
* update left separator color
*
* @param color
*/
void updateLeftSeparatorColor(int color);
/**
* update right separator color
*
* @param color
*/
void updateRightSeparatorColor(int color);
/**
* update top separator color
*
* @param color
*/
void updateTopSeparatorColor(int color);
/**
* update bottom separator color
*
* @param color
*/
void updateBottomSeparatorColor(int color);
boolean hasTopSeparator();
boolean hasRightSeparator();
boolean hasLeftSeparator();
boolean hasBottomSeparator();
boolean hasBorder();
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.link;
import android.view.View;
/**
* @author cginechen
* @date 2017-03-20
*/
public interface ITouchableSpan {
void setPressed(boolean pressed);
void onClick(View widget);
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.link;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.TextView;
import com.qmuiteam.qmui.BuildConfig;
import com.qmuiteam.qmui.widget.textview.ISpanTouchFix;
import java.lang.ref.WeakReference;
/**
* @author cginechen
* @date 2017-03-20
*/
public class QMUILinkTouchDecorHelper {
private WeakReference<ITouchableSpan> mPressedSpanRf;
public boolean onTouchEvent(TextView textView, Spannable spannable, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
ITouchableSpan span = getPressedSpan(textView, spannable, event);
if (span != null) {
span.setPressed(true);
Selection.setSelection(spannable, spannable.getSpanStart(span),
spannable.getSpanEnd(span));
mPressedSpanRf = new WeakReference<>(span);
}
if (textView instanceof ISpanTouchFix) {
ISpanTouchFix tv = (ISpanTouchFix) textView;
tv.setTouchSpanHit(span != null);
}
return span != null;
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
ITouchableSpan touchedSpan = getPressedSpan(textView, spannable, event);
ITouchableSpan recordSpan = null;
if (mPressedSpanRf != null){
recordSpan = mPressedSpanRf.get();
}
if(recordSpan != null && recordSpan != touchedSpan){
recordSpan.setPressed(false);
mPressedSpanRf = null;
recordSpan = null;
Selection.removeSelection(spannable);
}
if (textView instanceof ISpanTouchFix) {
ISpanTouchFix tv = (ISpanTouchFix) textView;
tv.setTouchSpanHit(recordSpan != null);
}
return recordSpan != null;
} else if (event.getAction() == MotionEvent.ACTION_UP) {
boolean touchSpanHint = false;
ITouchableSpan recordSpan = null;
if (mPressedSpanRf != null){
recordSpan = mPressedSpanRf.get();
}
if (recordSpan != null) {
touchSpanHint = true;
recordSpan.setPressed(false);
if(event.getAction() == MotionEvent.ACTION_UP){
recordSpan.onClick(textView);
}
}
mPressedSpanRf = null;
Selection.removeSelection(spannable);
if (textView instanceof ISpanTouchFix) {
ISpanTouchFix tv = (ISpanTouchFix) textView;
tv.setTouchSpanHit(touchSpanHint);
}
return touchSpanHint;
} else {
ITouchableSpan recordSpan = null;
if (mPressedSpanRf != null){
recordSpan = mPressedSpanRf.get();
}
if (recordSpan != null) {
recordSpan.setPressed(false);
}
if (textView instanceof ISpanTouchFix) {
ISpanTouchFix tv = (ISpanTouchFix) textView;
tv.setTouchSpanHit(false);
}
mPressedSpanRf = null;
Selection.removeSelection(spannable);
return false;
}
}
public ITouchableSpan getPressedSpan(TextView textView, Spannable spannable, MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= textView.getTotalPaddingLeft();
y -= textView.getTotalPaddingTop();
x += textView.getScrollX();
y += textView.getScrollY();
Layout layout = textView.getLayout();
int line = layout.getLineForVertical(y);
/*
* BugFix: https://issuetracker.google.com/issues/113348914
*/
try {
int off = layout.getOffsetForHorizontal(line, x);
if (x < layout.getLineLeft(line) || x > layout.getLineRight(line)) {
// 实际上没点到任何内容
off = -1;
}
ITouchableSpan[] link = spannable.getSpans(off, off, ITouchableSpan.class);
ITouchableSpan touchedSpan = null;
if (link.length > 0) {
touchedSpan = link[0];
}
return touchedSpan;
} catch (IndexOutOfBoundsException e) {
if (BuildConfig.DEBUG) {
Log.d(this.toString(), "getPressedSpan", e);
}
}
return null;
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.link;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.text.method.MovementMethod;
import android.text.method.Touch;
import android.view.MotionEvent;
import android.widget.TextView;
/**
* 配合 {@link QMUILinkTouchDecorHelper} 使用
*
* @author cginechen
* @date 2017-03-20
*/
public class QMUILinkTouchMovementMethod extends LinkMovementMethod {
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
return sHelper.onTouchEvent(widget, buffer, event)
|| Touch.onTouchEvent(widget, buffer, event);
}
public static MovementMethod getInstance() {
if (sInstance == null)
sInstance = new QMUILinkTouchMovementMethod();
return sInstance;
}
private static QMUILinkTouchMovementMethod sInstance;
private static QMUILinkTouchDecorHelper sHelper = new QMUILinkTouchDecorHelper();
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.link;
import android.text.Spannable;
import android.text.method.MovementMethod;
import android.text.method.ScrollingMovementMethod;
import android.text.method.Touch;
import android.view.MotionEvent;
import android.widget.TextView;
/**
* @author cginechen
* @date 2017-03-20
*/
public class QMUIScrollingMovementMethod extends ScrollingMovementMethod {
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
return sHelper.onTouchEvent(widget, buffer, event)
|| Touch.onTouchEvent(widget, buffer, event);
}
public static MovementMethod getInstance() {
if (sInstance == null)
sInstance = new QMUIScrollingMovementMethod();
return sInstance;
}
private static QMUIScrollingMovementMethod sInstance;
private static QMUILinkTouchDecorHelper sHelper = new QMUILinkTouchDecorHelper();
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.nestedScroll;
public interface IQMUIContinuousNestedBottomView extends IQMUIContinuousNestedScrollCommon {
int HEIGHT_IS_ENOUGH_TO_SCROLL = -1;
/**
* consume scroll
*
* @param dyUnconsumed the delta value to consume
*/
void consumeScroll(int dyUnconsumed);
void smoothScrollYBy(int dy, int duration);
void stopScroll();
/**
* sometimes the content of BottomView is not enough to scroll,
* so BottomView should tell the this info to {@link QMUIContinuousNestedScrollLayout}
*
* @return {@link #HEIGHT_IS_ENOUGH_TO_SCROLL} if can scroll, or content height.
*/
int getContentHeight();
int getCurrentScroll();
int getScrollOffsetRange();
}
\ No newline at end of file
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.nestedScroll;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public interface IQMUIContinuousNestedScrollCommon {
int SCROLL_STATE_IDLE = RecyclerView.SCROLL_STATE_IDLE;
int SCROLL_STATE_DRAGGING = RecyclerView.SCROLL_STATE_DRAGGING;
int SCROLL_STATE_SETTLING = RecyclerView.SCROLL_STATE_SETTLING;
void saveScrollInfo(@NonNull Bundle bundle);
void restoreScrollInfo(@NonNull Bundle bundle);
void injectScrollNotifier(OnScrollNotifier notifier);
interface OnScrollNotifier {
void notify(int innerOffset, int innerRange);
void onScrollStateChange(View view, int newScrollState);
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.nestedScroll;
public interface IQMUIContinuousNestedTopView extends IQMUIContinuousNestedScrollCommon {
/**
* consume scroll
*
* @param dyUnconsumed the delta value to consume
* @return the remain unconsumed value
*/
int consumeScroll(int dyUnconsumed);
int getCurrentScroll();
int getScrollOffsetRange();
}
\ No newline at end of file
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.nestedScroll;
import android.graphics.Rect;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.view.GravityCompat;
public class QMUIContinuousNestedBottomAreaBehavior extends QMUIViewOffsetBehavior<View> {
private final Rect tempRect1 = new Rect();
private final Rect tempRect2 = new Rect();
private int mTopInset = 0;
public void setTopInset(int topInset) {
mTopInset = topInset;
}
@Override
public boolean onMeasureChild(@NonNull CoordinatorLayout parent, @NonNull View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
final int childLpHeight = child.getLayoutParams().height;
if (childLpHeight == ViewGroup.LayoutParams.MATCH_PARENT
|| childLpHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
int availableHeight = View.MeasureSpec.getSize(parentHeightMeasureSpec);
if (availableHeight == 0) {
availableHeight = parent.getHeight();
}
availableHeight -= mTopInset;
final int heightMeasureSpec =
View.MeasureSpec.makeMeasureSpec(
availableHeight,
childLpHeight == ViewGroup.LayoutParams.MATCH_PARENT
? View.MeasureSpec.EXACTLY
: View.MeasureSpec.AT_MOST);
parent.onMeasureChild(
child, parentWidthMeasureSpec, widthUsed, heightMeasureSpec, heightUsed);
return true;
}
return false;
}
@Override
protected void layoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
List<View> dependencies = parent.getDependencies(child);
if (!dependencies.isEmpty()) {
View topView = dependencies.get(0);
final CoordinatorLayout.LayoutParams lp =
(CoordinatorLayout.LayoutParams) child.getLayoutParams();
final Rect available = tempRect1;
available.set(
parent.getPaddingLeft() + lp.leftMargin,
topView.getBottom() + lp.topMargin,
parent.getWidth() - parent.getPaddingRight() - lp.rightMargin,
parent.getHeight() + topView.getBottom() - parent.getPaddingBottom() - lp.bottomMargin);
final Rect out = tempRect2;
GravityCompat.apply(
resolveGravity(lp.gravity),
child.getMeasuredWidth(),
child.getMeasuredHeight(),
available,
out,
layoutDirection);
child.layout(out.left, out.top, out.right, out.bottom);
} else {
super.layoutChild(parent, child, layoutDirection);
}
}
@Override
public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
boolean ret = super.onLayoutChild(parent, child, layoutDirection);
List<View> dependencies = parent.getDependencies(child);
if (!dependencies.isEmpty()) {
View topView = dependencies.get(0);
setTopAndBottomOffset(topView.getBottom() - getLayoutTop());
}
return ret;
}
private static int resolveGravity(int gravity) {
return gravity == Gravity.NO_GRAVITY ? GravityCompat.START | Gravity.TOP : gravity;
}
@Override
public boolean layoutDependsOn(@NonNull CoordinatorLayout parent, @NonNull View child, @NonNull View dependency) {
return dependency instanceof IQMUIContinuousNestedTopView;
}
@Override
public boolean onDependentViewChanged(@NonNull CoordinatorLayout parent, @NonNull View child, @NonNull View dependency) {
setTopAndBottomOffset(dependency.getBottom() - getLayoutTop());
return false;
}
}
\ No newline at end of file
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.nestedScroll;
import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class QMUIContinuousNestedBottomRecyclerView extends RecyclerView
implements IQMUIContinuousNestedBottomView {
public static final String KEY_SCROLL_INFO_POSITION = "@qmui_scroll_info_bottom_rv_pos";
public static final String KEY_SCROLL_INFO_OFFSET = "@qmui_scroll_info_bottom_rv_offset";
private IQMUIContinuousNestedBottomView.OnScrollNotifier mOnScrollNotifier;
private final int[] mScrollConsumed = new int[2];
public QMUIContinuousNestedBottomRecyclerView(@NonNull Context context) {
super(context);
init();
}
public QMUIContinuousNestedBottomRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public QMUIContinuousNestedBottomRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
setVerticalScrollBarEnabled(false);
addOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
if (mOnScrollNotifier != null) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
mOnScrollNotifier.onScrollStateChange(recyclerView,
IQMUIContinuousNestedScrollCommon.SCROLL_STATE_IDLE);
} else if (newState == RecyclerView.SCROLL_STATE_SETTLING) {
mOnScrollNotifier.onScrollStateChange(recyclerView,
IQMUIContinuousNestedScrollCommon.SCROLL_STATE_SETTLING);
} else if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
mOnScrollNotifier.onScrollStateChange(recyclerView,
IQMUIContinuousNestedScrollCommon.SCROLL_STATE_DRAGGING);
}
}
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
if (mOnScrollNotifier != null) {
mOnScrollNotifier.notify(
recyclerView.computeVerticalScrollOffset(),
Math.max(0, recyclerView.computeVerticalScrollRange() - recyclerView.getHeight()));
}
}
});
}
@Override
public void consumeScroll(int yUnconsumed) {
if (yUnconsumed == Integer.MIN_VALUE) {
scrollToPosition(0);
} else if (yUnconsumed == Integer.MAX_VALUE) {
Adapter adapter = getAdapter();
if (adapter != null) {
scrollToPosition(adapter.getItemCount() - 1);
}
} else {
boolean reStartNestedScroll = false;
if (!hasNestedScrollingParent(ViewCompat.TYPE_TOUCH)) {
// the scrollBy use ViewCompat.TYPE_TOUCH to handle nested scroll...
reStartNestedScroll = true;
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_TOUCH);
// and scrollBy only call dispatchNestedScroll, not call dispatchNestedPreScroll
mScrollConsumed[0] = 0;
mScrollConsumed[1] = 0;
dispatchNestedPreScroll(0, yUnconsumed, mScrollConsumed, null, ViewCompat.TYPE_TOUCH);
yUnconsumed -= mScrollConsumed[1];
}
scrollBy(0, yUnconsumed);
if (reStartNestedScroll) {
stopNestedScroll(ViewCompat.TYPE_TOUCH);
}
}
}
@Override
public int getContentHeight() {
Adapter adapter = getAdapter();
if (adapter == null) {
return 0;
}
LayoutManager layoutManager = getLayoutManager();
if (layoutManager == null) {
return 0;
}
final int scrollRange = this.computeVerticalScrollRange();
if (scrollRange > getHeight()) {
return HEIGHT_IS_ENOUGH_TO_SCROLL;
}
return scrollRange;
}
@Override
public void injectScrollNotifier(OnScrollNotifier notifier) {
mOnScrollNotifier = notifier;
}
@Override
public int getCurrentScroll() {
return computeVerticalScrollOffset();
}
@Override
public int getScrollOffsetRange() {
return Math.max(0, computeVerticalScrollRange() - getHeight());
}
@Override
public void smoothScrollYBy(int dy, int duration) {
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_NON_TOUCH);
smoothScrollBy(0, dy, null);
}
@Override
public void saveScrollInfo(@NonNull Bundle bundle) {
LayoutManager layoutManager = getLayoutManager();
if (layoutManager instanceof LinearLayoutManager) {
LinearLayoutManager lm = (LinearLayoutManager) layoutManager;
int pos = lm.findFirstVisibleItemPosition();
View firstView = lm.findViewByPosition(pos);
int offset = firstView == null ? 0 : firstView.getTop();
bundle.putInt(KEY_SCROLL_INFO_POSITION, pos);
bundle.putInt(KEY_SCROLL_INFO_OFFSET, offset);
}
}
@Override
public void restoreScrollInfo(@NonNull Bundle bundle) {
LayoutManager layoutManager = getLayoutManager();
if (layoutManager instanceof LinearLayoutManager) {
int pos = bundle.getInt(KEY_SCROLL_INFO_POSITION, 0);
int offset = bundle.getInt(KEY_SCROLL_INFO_OFFSET, 0);
((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(pos, offset);
if(mOnScrollNotifier != null){
mOnScrollNotifier.notify(getCurrentScroll(), getScrollOffsetRange());
}
}
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.nestedScroll;
import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
import com.qmuiteam.qmui.layout.QMUILinearLayout;
import androidx.annotation.NonNull;
public class QMUIContinuousNestedTopLinearLayout extends QMUILinearLayout implements IQMUIContinuousNestedTopView {
public QMUIContinuousNestedTopLinearLayout(Context context) {
super(context);
}
public QMUIContinuousNestedTopLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public QMUIContinuousNestedTopLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public int consumeScroll(int dyUnconsumed) {
return dyUnconsumed;
}
@Override
public int getCurrentScroll() {
return 0;
}
@Override
public int getScrollOffsetRange() {
return 0;
}
@Override
public void injectScrollNotifier(OnScrollNotifier notifier) {
}
@Override
public void restoreScrollInfo(@NonNull Bundle bundle) {
}
@Override
public void saveScrollInfo(@NonNull Bundle bundle) {
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qmuiteam.qmui.nestedScroll;
import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class QMUIContinuousNestedTopRecyclerView extends RecyclerView implements IQMUIContinuousNestedTopView {
public static final String KEY_SCROLL_INFO_POSITION = "@qmui_scroll_info_top_rv_pos";
public static final String KEY_SCROLL_INFO_OFFSET = "@qmui_scroll_info_top_rv_offset";
private OnScrollNotifier mScrollNotifier;
private final int[] mScrollConsumed = new int[2];
public QMUIContinuousNestedTopRecyclerView(@NonNull Context context) {
this(context, null);
init();
}
public QMUIContinuousNestedTopRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
init();
}
public QMUIContinuousNestedTopRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init(){
setVerticalScrollBarEnabled(false);
}
@Override
public int consumeScroll(int dyUnconsumed) {
if (dyUnconsumed == Integer.MIN_VALUE) {
scrollToPosition(0);
return Integer.MIN_VALUE;
} else if (dyUnconsumed == Integer.MAX_VALUE) {
Adapter adapter = getAdapter();
if (adapter != null) {
scrollToPosition(adapter.getItemCount() - 1);
}
return Integer.MAX_VALUE;
}
boolean reStartNestedScroll = false;
if (!hasNestedScrollingParent(ViewCompat.TYPE_TOUCH)) {
// the scrollBy use ViewCompat.TYPE_TOUCH to handle nested scroll...
reStartNestedScroll = true;
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_TOUCH);
// and scrollBy only call dispatchNestedScroll, not call dispatchNestedPreScroll
mScrollConsumed[0] = 0;
mScrollConsumed[1] = 0;
dispatchNestedPreScroll(0, dyUnconsumed, mScrollConsumed, null, ViewCompat.TYPE_TOUCH);
dyUnconsumed -= mScrollConsumed[1];
}
scrollBy(0, dyUnconsumed);
if (reStartNestedScroll) {
stopNestedScroll(ViewCompat.TYPE_TOUCH);
}
return 0;
}
@Override
public int getCurrentScroll() {
return computeVerticalScrollOffset();
}
@Override
public int getScrollOffsetRange() {
return Math.max(0, computeVerticalScrollRange() - getHeight());
}
@Override
public void injectScrollNotifier(OnScrollNotifier notifier) {
mScrollNotifier = notifier;
}
@Override
public void onScrolled(int dx, int dy) {
super.onScrolled(dx, dy);
if(mScrollNotifier != null){
mScrollNotifier.notify(getCurrentScroll(), getScrollOffsetRange());
}
}
@Override
public void saveScrollInfo(@NonNull Bundle bundle) {
LayoutManager layoutManager = getLayoutManager();
if (layoutManager instanceof LinearLayoutManager) {
LinearLayoutManager lm = (LinearLayoutManager) layoutManager;
int pos = lm.findFirstVisibleItemPosition();
View firstView = lm.findViewByPosition(pos);
int offset = firstView == null ? 0 : firstView.getTop();
bundle.putInt(KEY_SCROLL_INFO_POSITION, pos);
bundle.putInt(KEY_SCROLL_INFO_OFFSET, offset);
}
}
@Override
public void restoreScrollInfo(@NonNull Bundle bundle) {
LayoutManager layoutManager = getLayoutManager();
if (layoutManager instanceof LinearLayoutManager) {
int pos = bundle.getInt(KEY_SCROLL_INFO_POSITION, 0);
int offset = bundle.getInt(KEY_SCROLL_INFO_OFFSET, 0);
((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(pos, offset);
if(mScrollNotifier != null){
mScrollNotifier.notify(getCurrentScroll(), getScrollOffsetRange());
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment