Repository: GIVEWAYTO/TagImageView
Branch: master
Commit: b6b021164e46
Files: 36
Total size: 66.2 KB
Directory structure:
gitextract_c4rl830d/
├── .gitignore
├── .idea/
│ ├── gradle.xml
│ ├── misc.xml
│ ├── modules.xml
│ └── runConfigurations.xml
├── README.md
├── app/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── com/
│ │ └── ken/
│ │ └── tagimage/
│ │ └── ExampleInstrumentedTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── ken/
│ │ │ └── tagimage/
│ │ │ ├── Density.java
│ │ │ ├── MainActivity.java
│ │ │ ├── TagImageView.java
│ │ │ ├── TagInfoBean.java
│ │ │ ├── TagTextView.java
│ │ │ └── ViewDialogFragment.java
│ │ └── res/
│ │ ├── drawable/
│ │ │ ├── ic_android_black_24dp.xml
│ │ │ └── ic_launcher_background.xml
│ │ ├── drawable-v24/
│ │ │ └── ic_launcher_foreground.xml
│ │ ├── layout/
│ │ │ ├── activity_main.xml
│ │ │ ├── dialog_add_tag.xml
│ │ │ └── image_tag.xml
│ │ ├── mipmap-anydpi-v26/
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ └── values/
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test/
│ └── java/
│ └── com/
│ └── ken/
│ └── tagimage/
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild
================================================
FILE: .idea/gradle.xml
================================================
================================================
FILE: .idea/misc.xml
================================================
================================================
FILE: .idea/modules.xml
================================================
================================================
FILE: .idea/runConfigurations.xml
================================================
================================================
FILE: README.md
================================================
# 高仿小红书之标签添加功能
- 随点击处添加标签
- 计算标签位置
- 可将标签位置还原渲染至不同屏幕尺寸
- 拖拽删除标签
- 可拖拽时支持点击标签更换文字方向
- 不可拖拽时支持点击标签响应点击事件
未做的:
当标签贴边,文字框将会收缩。
## 效果图

### Log

## 圆点相关数据
圆点坐标 x == 348 , y == 825
圆点在图片上的坐标百分比% x == 0.32222223 , y == 0.5729167
圆点数据:
TagInfoBean{
name='¥55 粉色衣服',
notesTagType=3,
url='tag点的链接url',
x=0.3222222328186035,
y=0.5729166865348816,
width=1080.0,
height=1440.0,
picWidth=1010.0,
picHeight=1324.0,
notesTagId=652,
isLeft=true,
isCanMove=true,
index=1
}
## Bean
private String name; //标签内容
private int notesTagType; //标签type
private String url; //标签url
private double x; //圆心x的在父控件位置 %
private double y; //圆心y的在父控件位置 %
private float width; //控件宽度
private float height; //控件高度
private float picWidth; //图片的宽度
private float picHeight; //图片的高度
private int notesTagId; //标签id
private boolean isLeft = true; //圆点是否在左边
private boolean isCanMove = true; //标签是否可以移动
private int index; //用来记录在编辑标签中的index 位置
================================================
FILE: app/.gitignore
================================================
/build
================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.ken.tagimage"
minSdkVersion 16
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27+'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# 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 *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
================================================
FILE: app/src/androidTest/java/com/ken/tagimage/ExampleInstrumentedTest.java
================================================
package com.ken.tagimage;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see Testing documentation
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.ken.tagimage", appContext.getPackageName());
}
}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
================================================
FILE: app/src/main/java/com/ken/tagimage/Density.java
================================================
/*
* Copyright (c) 2014,KJFrameForAndroid Open Source Project,张涛.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.ken.tagimage;
import android.content.Context;
import android.util.DisplayMetrics;
/**
* 作者: by KEN on 2018/7/14 17.
* 邮箱: gr201655@163.com
*/
public final class Density {
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
public static float dip2pxForFloat(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 sp
*/
public static int px2sp(Context context, float pxValue) {
float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
}
/**
* 根据手机的分辨率从 sp 的单位 转成为 px
*/
public static int sp2px(Context context, float spValue) {
float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
/**
* 获取dialog宽度
*/
public static int getDialogW(Context aty) {
DisplayMetrics dm = new DisplayMetrics();
dm = aty.getResources().getDisplayMetrics();
int w = dm.widthPixels - 100;
// int w = aty.getWindowManager().getDefaultDisplay().getWidth() - 100;
return w;
}
/**
* 获取屏幕宽度
*/
public static int getScreenW(Context aty) {
DisplayMetrics dm = new DisplayMetrics();
dm = aty.getResources().getDisplayMetrics();
int w = dm.widthPixels;
// int w = aty.getWindowManager().getDefaultDisplay().getWidth();
return w;
}
/**
* 获取屏幕高度
*/
public static int getScreenH(Context aty) {
DisplayMetrics dm = new DisplayMetrics();
dm = aty.getResources().getDisplayMetrics();
int h = dm.heightPixels;
// int h = aty.getWindowManager().getDefaultDisplay().getHeight();
return h;
}
}
================================================
FILE: app/src/main/java/com/ken/tagimage/MainActivity.java
================================================
package com.ken.tagimage;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private int imageH;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
//禁止横屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.activity_main);
final TagImageView tag_view = findViewById(R.id.tag_content);
tag_view.setClickTagListener(new TagImageView.ClickTagListener() {
@Override
public void click(TagInfoBean bean) {
Toast.makeText(MainActivity.this, "标签被点击 == " + bean.getName(), Toast.LENGTH_SHORT).show();
}
});
//添加标签
tag_view.setAddTagListener(new TagImageView.AddTagListener() {
@Override
public void addTag(String path, double rawX, double rawY) {
final TagInfoBean bean = new TagInfoBean();
bean.setCanMove(true);
bean.setNotesTagId(652);
bean.setNotesTagType(TagTextView.TAG_TEXT);
//通过手机中的图片地址 或者 网络拉取的图片信息 获得图片宽高
bean.setPicWidth(1010);
bean.setPicHeight(1324);
bean.setUrl("tag点的链接url");
// 显示控件的显示 依照图片的本身的宽高比例进行动态设置
bean.setWidth(Density.getScreenW(MainActivity.this));
//标签在控件上的比例
bean.setLeft(!(rawX > bean.getWidth()/ 2));
bean.setX(rawX / bean.getWidth());
bean.setY(rawY / imageH);
bean.setHeight(imageH);
ViewDialogFragment dialogFragment = new ViewDialogFragment();
dialogFragment.setCallback(new ViewDialogFragment.Callback() {
@Override
public void onClick(String tabName) {
if (TextUtils.isEmpty(tabName))
tabName = "女孩";
bean.setName(tabName);
Log.e("zz", "onClick: "+bean.getName() + " " + imageH );
tag_view.addTag(bean);
}
});
dialogFragment.show(getSupportFragmentManager());
}
});
//删除标签
tag_view.setDeleteTagListener(new TagImageView.DeleteTagListener() {
@Override
public void remove(String path, TagInfoBean bean) {
Toast.makeText(MainActivity.this, "删除标签 == " + bean.getName(), Toast.LENGTH_SHORT).show();
}
});
//设置图片的路径
tag_view.setPath("一般是本地图片地址,这里用的是资源图片"); //可用来标记这些标签属于哪张图片
//添加初始标签
List tagInfoBeanList = new ArrayList<>();
tagInfoBeanList.add(createTag1());
tagInfoBeanList.add(createTag2());
tagInfoBeanList.add(createTag3());
//设置 图片的高度 可根据实际的图片高度比例 设置
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, imageH);
findViewById(R.id.image).setLayoutParams(params);
tag_view.setLayoutParams(params);
tag_view.setTagList(tagInfoBeanList);
}
@NonNull
private TagInfoBean createTag1() {
TagInfoBean bean = new TagInfoBean();
//该标签是否可以移动
bean.setCanMove(false);
bean.setLeft(false);
bean.setName("一杯奶茶");
bean.setNotesTagId(652);
bean.setNotesTagType(TagTextView.TAG_BRAND);
//通过手机中的图片地址 或者 网络拉取的图片信息 获得图片宽高
bean.setPicWidth(1010);
bean.setPicHeight(1324);
bean.setUrl("tag点的链接url");
// 显示控件的显示 依照图片的本身的宽高比例进行动态设置
bean.setWidth(Density.getScreenW(this));
imageH = 0;
//项目中需求是只有1:1 和 3:4的比例 这个可根据实际修改 直接按图片比例也可以
if (bean.getPicWidth() / bean.getPicHeight() > 0.85f) {
imageH = (int) bean.getWidth();
} else {
imageH = (int) (bean.getWidth() * 4 / 3);
}
//标签原点在照片上的比例
bean.setX(0.7513889);
bean.setY(0.5864583);
bean.setHeight(imageH);
return bean;
}
@NonNull
private TagInfoBean createTag2() {
TagInfoBean bean = new TagInfoBean();
bean.setCanMove(true);
bean.setLeft(true);
bean.setName("¥55 粉色衣服");
bean.setNotesTagId(652);
bean.setNotesTagType(TagTextView.TAG_PRICE);
//通过手机中的图片地址 或者 网络拉取的图片信息 获得图片宽高
bean.setPicWidth(1010);
bean.setPicHeight(1324);
bean.setUrl("tag点的链接url");
// 显示控件的显示 依照图片的本身的宽高比例进行动态设置
bean.setWidth(Density.getScreenW(this));
imageH = 0;
//项目中需求是只有1:1 和 3:4的比例 这个可根据实际修改 直接按图片比例也可以
if (bean.getPicWidth() / bean.getPicHeight() > 0.85f) {
imageH = (int) bean.getWidth();
} else {
imageH = (int) (bean.getWidth() * 4 / 3);
}
//标签原点在照片上的比例
bean.setX(0.5625);
bean.setY(0.81041664);
bean.setHeight(imageH);
return bean;
}
@NonNull
private TagInfoBean createTag3() {
TagInfoBean bean = new TagInfoBean();
bean.setCanMove(true);
bean.setLeft(true);
bean.setName("大眼睛");
bean.setNotesTagId(652);
bean.setNotesTagType(TagTextView.TAG_BRAND);
//通过手机中的图片地址 或者 网络拉取的图片信息 获得图片宽高
bean.setPicWidth(1010);
bean.setPicHeight(1324);
bean.setUrl("tag点的链接url");
// 显示控件的显示 依照图片的本身的宽高比例进行动态设置
bean.setWidth(Density.getScreenW(this));
imageH = 0;
//计算图片的高度 因为项目中需求是图片只有1:1 和 3:4的比例 这个可根据实际修改 直接按图片比例也可以
if (bean.getPicWidth() / bean.getPicHeight() > 0.85f) {
imageH = (int) bean.getWidth();
} else {
imageH = (int) (bean.getWidth() * 4 / 3);
}
//标签原点在照片上的比例
bean.setX(0.35833332);
bean.setY(0.29583332);
bean.setHeight(imageH);
return bean;
}
}
================================================
FILE: app/src/main/java/com/ken/tagimage/TagImageView.java
================================================
package com.ken.tagimage;
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.CycleInterpolator;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import java.util.ArrayList;
import java.util.List;
/**
* 作者: by KEN on 2018/7/14 17.
* 邮箱: gr201655@163.com
*/
public class TagImageView extends FrameLayout {
private RelativeLayout mContentLayout;
private Paint mOvalPaint;
private float topPadding;
private int leftPading;
private int mRadius;
private int lineLong;
private View mDelete_tags;
private TagTextView.TagGestureListener tagClickListener;
private boolean isClick = false;
private String mPath;
/**
* 标签数据 最后只要重新设置每个标签当前的位置
* 标签有可能被编辑 所以要获取最后的位置 即可
* 如果标签是不可移动的属性 则不需要更新
*/
private List infoBeanList = new ArrayList<>();
public TagImageView(Context context) {
this(context, null);
}
public TagImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TagImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
private void initView(Context context) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.image_tag, this, true);
mDelete_tags = findViewById(R.id.delete_tags);
mDelete_tags.setVisibility(View.GONE);
mContentLayout = (RelativeLayout) findViewById(R.id.tagsGroup);
mOvalPaint = new Paint();
mOvalPaint.setTextSize(Density.sp2px(context, 14));
mOvalPaint.setStrokeWidth(Density.dip2px(context, 1));
mOvalPaint.setFilterBitmap(true);
//滑动
mContentLayout.setOnTouchListener(onTouchListener);
//边框与文字顶部底部的距离
topPadding = Density.dip2px(context, 3);
leftPading = Density.dip2px(context, 6);
mRadius = Density.dip2px(context, 4);
//线长
lineLong = Density.dip2px(context, 15);
//标签手势监听
tagClickListener = new TagTextView.TagGestureListener() {
@Override
public void onDown(View view, TagInfoBean bean) {
if (mDelete_tags.getVisibility() == View.GONE && bean.isCanMove()) {
mDelete_tags.setVisibility(View.VISIBLE);
}
}
@Override
public void onUp(View view, TagInfoBean bean) {
if (mDelete_tags.getVisibility() == View.VISIBLE) {
mDelete_tags.setVisibility(View.GONE);
}
}
@Override
public void clickTag(View view, TagInfoBean bean) {
if(mClickTagListener!=null)
mClickTagListener.click(bean);
}
@Override
public void inDeleteRect(View view, TagInfoBean bean) {
mContentLayout.removeView(view);
infoBeanList.remove(bean);
//移除的监听
if (mDeleteTagListener != null) mDeleteTagListener.remove(mPath, bean);
}
@Override
public void move(View view, TagInfoBean bean) {
}
};
}
float mLastX;
float downX;
float downY;
OnTouchListener onTouchListener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getRawX();
downY = event.getRawY();
mLastX = event.getX();
isClick = true;
break;
case MotionEvent.ACTION_UP:
if (isClick) {
double rawX = event.getRawX();
double rawY = event.getRawY();
mAddTagListener.addTag(mPath, downX, downY);
}
break;
case MotionEvent.ACTION_MOVE:
if (isClick && Math.abs(event.getX() - mLastX) > 50f) {
isClick = false;
}
return false;
}
return true;
}
};
public void addTag(TagInfoBean infoBean) {
infoBeanList.add(infoBean);
createTags(infoBean);
}
public void setAddTagListener(AddTagListener addTagListener) {
mAddTagListener = addTagListener;
}
public void setDeleteTagListener(DeleteTagListener deleteTagListener) {
mDeleteTagListener = deleteTagListener;
}
/**
* 添加标签
*/
private AddTagListener mAddTagListener;
public interface AddTagListener {
void addTag(String path, double rawX, double rawY);
}
/**
* 删除标签
*/
private DeleteTagListener mDeleteTagListener;
public interface DeleteTagListener {
void remove(String path, TagInfoBean bean);
}
/**
* 标签被点击
*/
private ClickTagListener mClickTagListener;
public void setClickTagListener(ClickTagListener mClickTagListener) {
this.mClickTagListener = mClickTagListener;
}
public interface ClickTagListener {
void click(TagInfoBean bean);
}
/**
* 图片在本地的地址
*
* @param path
*/
public void setPath(String path) {
mPath = path;
}
public String getPath() {
return mPath;
}
public void setTagList(List list) {
clearTags();
int num = 0;//用于计数
infoBeanList = list;
for (TagInfoBean bean : list) {
if (TextUtils.isEmpty(bean.getName())) {
continue;
}
bean.setIndex(num++);
createTags(bean);
}
}
private void createTags(TagInfoBean bean) {
//获取文本的宽高
final Rect bounds = new Rect();
String name = bean.getName();
if (name.length() > 16) {
name = name.substring(0, 16) + "...";
}
mOvalPaint.getTextBounds(name, 0, name.length(), bounds);
//获得边框的宽高
final float mStokeHeight = bounds.bottom - bounds.top + topPadding * 2;
int left = 0;
int top = 0;
top = (int) (bean.getHeight() * bean.getY() - mStokeHeight / 2);
if (bean.isLeft()) {
left = (int) (bean.getWidth() * bean.getX() - mRadius);
} else {
int mStokeWidth = bounds.right - bounds.left + leftPading * 2 + (bounds.bottom - bounds.top);
left = (int) (bean.getWidth() * bean.getX() - mStokeWidth - lineLong);
}
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout
.LayoutParams
.WRAP_CONTENT);
params.setMargins(left, top, 0, 0);
final TagTextView child = new TagTextView(getContext(), bean);
child.setTagGestureListener(tagClickListener);
mContentLayout.addView(child, params);
}
private void clearTags() {
mContentLayout.removeAllViews();
}
}
================================================
FILE: app/src/main/java/com/ken/tagimage/TagInfoBean.java
================================================
package com.ken.tagimage;
/**
* 作者: by KEN on 2018/7/14 17.
* 邮箱: gr201655@163.com
*
* 由于项目为统一跟后台定义字段相同 有部分命名不准确
*/
public class TagInfoBean {
private String name; //标签内容
private int notesTagType; //标签type
private String url; //标签url
private double x; //圆心x的在父控件位置 %
private double y; //圆心y的在父控件位置 %
private float width; //控件宽度
private float height; //控件高度
private float picWidth; //图片的宽度
private float picHeight; //图片的高度
private int notesTagId; //标签id
private boolean isLeft = true; //圆点是否在左边
private boolean isCanMove = true; //标签是否可以移动
private int index; //用来记录在编辑标签中的index 位置
public void setCanMove(boolean canMove) {
isCanMove = canMove;
}
public boolean isCanMove() {
return isCanMove;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNotesTagType() {
return notesTagType;
}
public void setNotesTagType(int notesTagType) {
this.notesTagType = notesTagType;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public float getPicWidth() {
return picWidth;
}
public void setPicWidth(float picWidth) {
this.picWidth = picWidth;
}
public float getPicHeight() {
return picHeight;
}
public void setPicHeight(float picHeight) {
this.picHeight = picHeight;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
public float getWidth() {
return width;
}
public void setWidth(float width) {
this.width = width;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
public int getNotesTagId() {
return notesTagId;
}
public void setNotesTagId(int notesTagId) {
this.notesTagId = notesTagId;
}
public boolean isLeft() {
return isLeft;
}
public void setLeft(boolean left) {
isLeft = left;
}
public void setIndex(int index) {
this.index = index;
}
public int getIndex() {
return index;
}
@Override
public String toString() {
return "TagInfoBean{" +
"name='" + name + '\'' +
", notesTagType=" + notesTagType +
", url='" + url + '\'' +
", x=" + x +
", y=" + y +
", width=" + width +
", height=" + height +
", picWidth=" + picWidth +
", picHeight=" + picHeight +
", notesTagId=" + notesTagId +
", isLeft=" + isLeft +
", isCanMove=" + isCanMove +
", index=" + index +
'}';
}
}
================================================
FILE: app/src/main/java/com/ken/tagimage/TagTextView.java
================================================
package com.ken.tagimage;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.v4.view.GestureDetectorCompat;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
/**
* 作者: by KEN on 2018/7/14 17.
* 邮箱: gr201655@163.com
*/
public class TagTextView extends View {
private Paint ovalPaint = new Paint();
private float mRadius = 0; //外圆半径
private float mInnerRadius = 0; //内圆半径
private RectF mCenterRect;
private int lineLong = 0; //横线的长度
private RectF mTextRoundRect; //文字框内容高度
private String textContent; //文本内容
private final int TextMaxNum = 16; //文本最多显示16个文字
private GestureDetectorCompat mGestureDetector;
private float mStokeHeight; //边框的高度
private float mStokeWidth; //边框的宽度
private float mCircleY; //中心圆的高度
private float leftPadding;
private float mTextX; //文字起始x
private float mTextY; //文字baseline的高度
private int mRoundX;
private float mFirstDownX;
private float mFirstDownY;
private int leftBorder = 0; //上边界 左边界
private int rightBorder = 0; //右边界
private int bottomBorder = 0; //底部边界
private int circleX = 0; //中心圆的x坐标
private int circleY = 0; //中心圆的y坐标
private int parentWidth = 0; //父级的宽度
private int parentHeight = 0; //父级的高度
private float percentX = 0f; //在父级的宽度占比
private float percentY = 0f; //在父级的高度占比
private boolean isLeft = true; //圆点是否在左边
private TagInfoBean mTagInfoBean;
private int mShadeColor;
public static final int TAG_TEXT = 0; //一般
public static final int TAG_LOCATION = 1; //地址
public static final int TAG_BRAND = 2; //品牌
public static final int TAG_PRICE = 3; //价格
private boolean mCanMove = true; //可以被移动
private float tempX; // 临时记录按键按下的位置
private float tempY;
private Bitmap mBitmap;
private float mTopPadding;
private RectF mTypeIconRect;
private int mIconWidth;
private boolean isMoveXY = false; // 用来记录是否被移动过 如果没有则不改变数据中的 xy百分比
private RectF deleteRect; //用来判断是否滑动到底部
private PaintFlagsDrawFilter pfd;
public TagInfoBean getTagInfoBean() {
if (isMoveXY) {
mTagInfoBean.setX(percentX);
mTagInfoBean.setY(percentY);
}
return mTagInfoBean;
}
public TagTextView(Context context, TagInfoBean tagInfoBean) {
this(context, null, 0);
mTagInfoBean = tagInfoBean;
initView(context);
}
public TagTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TagTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
private void initView(Context context) {
if (mTagInfoBean == null) return;
//在1+手机滑动时出现了残影 也有可能是硬件加速的问题
// setFadingEdgeLength(0);
// setLayerType(View.LAYER_TYPE_SOFTWARE, null);
ovalPaint.setAntiAlias(true);
ovalPaint.setStyle(Paint.Style.FILL);
ovalPaint.setColor(Color.WHITE);
ovalPaint.setStrokeWidth(Density.dip2px(context, 1));
mTextRoundRect = new RectF();
mShadeColor = Color.parseColor("#30ffffff");
mRadius = Density.dip2px(context, 4);
mInnerRadius = Density.dip2px(context, 2.5f);
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
switch (mTagInfoBean.getNotesTagType()) {
case TAG_LOCATION:
mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.tags_location, opts);
break;
case TAG_BRAND:
mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.brand, opts);
break;
case TAG_PRICE:
mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.price, opts);
break;
default:
mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.tags_text, opts);
break;
}
//防止bitmap 变模糊
ovalPaint.setFilterBitmap(true);
ovalPaint.setAntiAlias(true);
ovalPaint.setStrokeWidth(Density.dip2px(getContext(),1));
pfd = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
ovalPaint.setTextSize(Density.dip2px(context, 14));
lineLong = Density.dip2px(context, 15);
textContent = mTagInfoBean.getName();
if (TextUtils.isEmpty(textContent)) return;
if (textContent.length() > TextMaxNum) {
textContent = textContent.substring(0, TextMaxNum - 1) + "...";
}
mCanMove = mTagInfoBean.isCanMove();
rightBorder = Density.getScreenW(context);
//获取文本的宽高
Rect bounds = new Rect();
ovalPaint.getTextBounds(textContent, 0, textContent.length(), bounds);
//边框与文字顶部底部的距离
mTopPadding = Density.dip2px(context, 3);
//边框与文字左右的距离
leftPadding = Density.dip2px(context, 6);
isLeft = mTagInfoBean.isLeft();
//标签类别icon
mTypeIconRect = new RectF();
int iconHeight = bounds.bottom - bounds.top;
mIconWidth = iconHeight;
mTypeIconRect.set(lineLong + mRadius + leftPadding, mTopPadding, lineLong + mRadius + mIconWidth + leftPadding, mTopPadding + iconHeight);
//获得边框的宽高
mStokeHeight = bounds.bottom - bounds.top + mTopPadding * 2;
mStokeWidth = bounds.right - bounds.left + leftPadding * 2 + mIconWidth;
//文字Rect的大小
mTextRoundRect.set(lineLong + mRadius, 0, lineLong + mRadius + mStokeWidth, mStokeHeight);
//圆心y
mCircleY = mStokeHeight / 2;
//文字起始x
mTextX = lineLong + mRadius + leftPadding + mIconWidth;
//文字y
Paint.FontMetricsInt fontMetrics = ovalPaint.getFontMetricsInt();
mTextY = (mTextRoundRect.top + mTextRoundRect.bottom - fontMetrics.bottom -
fontMetrics.top) / 2;
//整个的控件的位置
mCenterRect = new RectF();
mCenterRect.set(0, 0, mRadius + lineLong + mStokeWidth, mStokeHeight);
//手势监听
mGestureDetector = new GestureDetectorCompat(context, mGestureListener);
mGestureDetector.setIsLongpressEnabled(false);
parentWidth = rightBorder;
parentHeight = (int) mTagInfoBean.getHeight();
bottomBorder = parentHeight;
//删除--控件的半径
int delet_raduis = Density.dip2px(context, 15);
float top = parentHeight - Density.dip2px(context, 80) - mStokeHeight / 2;
//删除图标的大小
deleteRect = new RectF(rightBorder / 2 - (lineLong + mStokeWidth + delet_raduis), top,
rightBorder / 2 + delet_raduis, parentHeight - Density.dip2px(context, 50) - mStokeHeight / 2);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
widthMeasureSpec = MeasureSpec.makeMeasureSpec((int) (mRadius + lineLong + mStokeWidth +ovalPaint.getStrokeWidth() * 2), MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) (mStokeHeight + ovalPaint.getStrokeWidth() * 2), MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//边框圆角半径
mRoundX = h / 2;
}
@Override
protected void onDraw(Canvas canvas) {
//绘制外圆
ovalPaint.setStyle(Paint.Style.FILL);
ovalPaint.setColor(mShadeColor);
//原点在左边
if (isLeft) {
canvas.drawCircle(mRadius, mCircleY + ovalPaint.getStrokeWidth(), mRadius, ovalPaint);
mTextRoundRect.set(lineLong + mRadius, ovalPaint.getStrokeWidth(), lineLong + mRadius + mStokeWidth, mStokeHeight + ovalPaint.getStrokeWidth() );
//画边框遮罩
canvas.drawRoundRect(mTextRoundRect, mRoundX, mRoundX, ovalPaint);
} else {
mTextRoundRect.set(ovalPaint.getStrokeWidth(), ovalPaint.getStrokeWidth(), mStokeWidth + ovalPaint.getStrokeWidth(), mStokeHeight + ovalPaint.getStrokeWidth());
canvas.drawCircle(mStokeWidth + lineLong, mCircleY+ ovalPaint.getStrokeWidth() , mRadius, ovalPaint);
//画边框遮罩
canvas.drawRoundRect(mTextRoundRect, mRoundX, mRoundX, ovalPaint);
}
canvas.setDrawFilter(pfd);
//绘制内圆
ovalPaint.setColor(Color.WHITE);
if (isLeft) {
canvas.drawCircle(mRadius, mCircleY+ ovalPaint.getStrokeWidth() , mInnerRadius, ovalPaint);
//画线
canvas.drawLine(mRadius, mStokeHeight / 2 + ovalPaint.getStrokeWidth(), lineLong + mRadius, mStokeHeight / 2 + ovalPaint.getStrokeWidth(), ovalPaint);
mTypeIconRect.set(lineLong + mRadius + leftPadding, mTopPadding + ovalPaint.getStrokeWidth(), lineLong + mRadius + mIconWidth + leftPadding, mTopPadding + mIconWidth + + ovalPaint.getStrokeWidth());
//画标签类型icon
canvas.drawBitmap(mBitmap, null, mTypeIconRect, ovalPaint);
//文字起始x
mTextX = lineLong + mRadius + leftPadding + mIconWidth;
//文字y
Paint.FontMetricsInt fontMetrics = ovalPaint.getFontMetricsInt();
mTextY = (mTextRoundRect.top + mTextRoundRect.bottom - fontMetrics.bottom -
fontMetrics.top) / 2;
canvas.drawText(textContent, mTextX, mTextY, ovalPaint);
//画边框
ovalPaint.setStyle(Paint.Style.STROKE);
canvas.drawRoundRect(mTextRoundRect, mRoundX, mRoundX, ovalPaint);
} else {
canvas.drawCircle(mStokeWidth + lineLong, mCircleY + ovalPaint.getStrokeWidth(), mInnerRadius, ovalPaint);
mTypeIconRect.set(leftPadding, mTopPadding + ovalPaint.getStrokeWidth(), mIconWidth + leftPadding, mTopPadding + mIconWidth + ovalPaint.getStrokeWidth());
//画标签类型icon
canvas.drawBitmap(mBitmap, null, mTypeIconRect, ovalPaint);
//画线
canvas.drawLine(mStokeWidth + ovalPaint.getStrokeWidth(), mStokeHeight / 2 + ovalPaint.getStrokeWidth(), mStokeWidth + lineLong, mStokeHeight / 2 + ovalPaint.getStrokeWidth(), ovalPaint);
//文字
mTextX = leftPadding + mIconWidth;
//文字y
Paint.FontMetricsInt fontMetrics = ovalPaint.getFontMetricsInt();
mTextY = (mTextRoundRect.top + mTextRoundRect.bottom - fontMetrics.bottom -
fontMetrics.top) / 2;
canvas.drawText(textContent, mTextX, mTextY, ovalPaint);
//画边框
ovalPaint.setStyle(Paint.Style.STROKE);
canvas.drawRoundRect(mTextRoundRect, mRoundX, mRoundX, ovalPaint);
}
super.onDraw(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP){
Log.e("zz","无判断条件ACTION_UP");
}
if (event.getAction() == MotionEvent.ACTION_UP && mCanMove && mTagGestureListener != null ) {
Log.e("zz","有判断条件ACTION_UP");
mTagGestureListener.onUp(this, mTagInfoBean);
float positionX = event.getRawX() - mFirstDownX - tempX;
float positionY = event.getRawY() - mFirstDownY - tempY;
if (positionX < leftBorder) {
positionX = leftBorder;
} else {
float viewWidth = rightBorder - mRadius - lineLong - mStokeWidth;
if (positionX > viewWidth) positionX = viewWidth;
}
if (positionY < 0) {
positionY = 0;
} else {
float viewHeight = bottomBorder - mStokeHeight;
if (positionY > viewHeight) positionY = viewHeight;
}
//处于删除区域
if (deleteRect.contains(positionX, positionY)) {
mTagGestureListener.inDeleteRect(TagTextView.this, mTagInfoBean);
}
}
return mGestureDetector.onTouchEvent(event);
}
public interface TagGestureListener {
/**
* 手指按下
*/
void onDown(View view, TagInfoBean bean);
/**
* 手指抬起
*/
void onUp(View view, TagInfoBean bean);
/**
* 点击了标签
*/
void clickTag(View view, TagInfoBean bean);
/**
* 在删除区域
*/
void inDeleteRect(View view, TagInfoBean bean);
/**
* 在滑动
*
* @param view
* @param bean
*/
void move(View view, TagInfoBean bean);
}
//标签文字内容被点击
private TagGestureListener mTagGestureListener;
public void setTagGestureListener(TagGestureListener tagClickListener) {
mTagGestureListener = tagClickListener;
}
private GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
if (mCanMove && mTagGestureListener != null)
mTagGestureListener.onDown(TagTextView.this, mTagInfoBean);
mFirstDownX = e.getX();
mFirstDownY = e.getY();
//记录父容器和手机屏幕左上角的x和y的值
tempX = e.getRawX() - e.getX() - TagTextView.this.getX();
tempY = e.getRawY() - e.getY() - TagTextView.this.getY();
return mCenterRect.contains(e.getX(), e.getY()) || super.onDown(e);
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
//标签被点击
if (mCanMove) {
//换方向
isLeft = !isLeft;
isMoveXY = true;
//重新记录点的位置
meausePercent();
invalidate();
} else if (mTextRoundRect.contains(e.getX(), e.getY())) {
if (!mCanMove && mTagGestureListener != null) { // 不可编辑状态
mTagGestureListener.clickTag(TagTextView.this, mTagInfoBean);
}
}
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//可以滑动编辑
if (mCanMove) {
float positionX = e2.getRawX() - mFirstDownX - tempX;
float positionY = e2.getRawY() - mFirstDownY - tempY;
if (positionX < leftBorder) {
positionX = leftBorder;
} else {
float viewWidth = rightBorder - mRadius - lineLong - mStokeWidth;
if (positionX > viewWidth) positionX = viewWidth;
}
if (positionY < 0) {
positionY = 0;
} else {
float viewHeight = bottomBorder - mStokeHeight;
if (positionY > viewHeight) positionY = viewHeight;
}
TagTextView.this.setX(positionX);
TagTextView.this.setY(positionY);
if (mCanMove && mTagGestureListener != null) {
mTagGestureListener.move(TagTextView.this, mTagInfoBean);
}
isMoveXY = true;
meausePercent();
return true;
} else {
return false;
}
}
};
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
//请求所有父控件及祖宗控件不要拦截事件
getParent().requestDisallowInterceptTouchEvent(true);
return super.dispatchTouchEvent(ev);
}
/**
* 计算圆心的坐标占比
*/
private void meausePercent() {
if (parentWidth == 0 || parentHeight == 0) return;
if (isLeft) {
circleX = (int) (getX() + mRadius);
circleY = (int) (getY() + mStokeHeight / 2 + ovalPaint.getStrokeWidth());
} else {
circleX = (int) (getX() + mStokeWidth + lineLong + ovalPaint.getStrokeWidth() );
circleY = (int) (getY() + mStokeHeight / 2 + ovalPaint.getStrokeWidth());
}
percentX = (((float) circleX) / parentWidth);
percentY = (((float) circleY) / parentHeight);
Log.e("zz", "圆点相关数据");
Log.e("zz", "圆点坐标 x == "+ circleX +" , y == " + circleY );
Log.e("zz", "圆点在图片上的坐标比例 x == "+ percentX +" , y == " + percentY );
Log.e("zz", "圆点数据:"+ getTagInfoBean().toString() );
}
}
================================================
FILE: app/src/main/java/com/ken/tagimage/ViewDialogFragment.java
================================================
package com.ken.tagimage;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
public class ViewDialogFragment extends DialogFragment {
public interface Callback {
void onClick(String tabName);
}
private Callback callback;
public void show(FragmentManager fragmentManager) {
show(fragmentManager, "ViewDialogFragment");
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
final View view = inflater.inflate(R.layout.dialog_add_tag, null);
final EditText tab_name = (EditText) view.findViewById(R.id.tab_name);
builder.setView(view)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (callback != null) {
callback.onClick(tab_name.getText().toString());
}
}
})
;
return builder.create();
}
public void setCallback(Callback callback) {
this.callback = callback;
}
@Override
public void onDestroy() {
super.onDestroy();
callback = null;
}
}
================================================
FILE: app/src/main/res/drawable/ic_android_black_24dp.xml
================================================
================================================
FILE: app/src/main/res/drawable/ic_launcher_background.xml
================================================
================================================
FILE: app/src/main/res/drawable-v24/ic_launcher_foreground.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_main.xml
================================================
================================================
FILE: app/src/main/res/layout/dialog_add_tag.xml
================================================
================================================
FILE: app/src/main/res/layout/image_tag.xml
================================================
================================================
FILE: app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
================================================
================================================
FILE: app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
================================================
================================================
FILE: app/src/main/res/values/colors.xml
================================================
#3F51B5
#303F9F
#FF4081
================================================
FILE: app/src/main/res/values/strings.xml
================================================
TagImage
================================================
FILE: app/src/main/res/values/styles.xml
================================================
================================================
FILE: app/src/test/java/com/ken/tagimage/ExampleUnitTest.java
================================================
package com.ken.tagimage;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see Testing documentation
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Tue Aug 14 13:35:27 CST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
================================================
FILE: gradle.properties
================================================
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
================================================
FILE: gradlew
================================================
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: settings.gradle
================================================
include ':app'