diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c6cbe56 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..8c870f5 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +SwipListView \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..96cc43e --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..97626ba --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..c51a1d7 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..1a3eaff --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..98b72f3 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..2991b52 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,29 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.3" + + defaultConfig { + applicationId "swipelistview.yjn.com.swiplistview" + minSdkVersion 15 + targetSdkVersion 23 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile project(':swipelistviewlibrary') + compile fileTree(dir: 'libs', include: ['*.jar']) + testCompile 'junit:junit:4.12' + compile 'com.android.support:appcompat-v7:23.3.0' + compile 'com.jakewharton:butterknife:6.1.0' + +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..d7adfc4 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in F:\ZTEsoft\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 *; +#} diff --git a/app/src/androidTest/java/swipelistview/yjn/com/swiplistview/ApplicationTest.java b/app/src/androidTest/java/swipelistview/yjn/com/swiplistview/ApplicationTest.java new file mode 100644 index 0000000..2fa2f59 --- /dev/null +++ b/app/src/androidTest/java/swipelistview/yjn/com/swiplistview/ApplicationTest.java @@ -0,0 +1,13 @@ +package swipelistview.yjn.com.swiplistview; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..f37fa9b --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/swipelistview/yjn/com/swiplistview/adapter/TransferAdapter.java b/app/src/main/java/swipelistview/yjn/com/swiplistview/adapter/TransferAdapter.java new file mode 100644 index 0000000..75f8462 --- /dev/null +++ b/app/src/main/java/swipelistview/yjn/com/swiplistview/adapter/TransferAdapter.java @@ -0,0 +1,89 @@ +package swipelistview.yjn.com.swiplistview.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.LinearLayout; +import android.widget.TextView; + +import java.util.HashMap; +import java.util.List; + +import butterknife.ButterKnife; +import butterknife.InjectView; +import swipelistview.yjn.com.swiplistview.R; +import swipelistview.yjn.com.swiplistview.util.StringUtil; + +/** + * Description: + * Author: 0027008122 [yang.jianan@zte.com.cn] + * Time: 2016/3/31 16:29 + * Version: 1.0 + */ +public class TransferAdapter extends BaseAdapter { + private Context context; + private List> data; + + public TransferAdapter(Context context, List> data) { + this.context = context; + this.data = data; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + ViewHolder mHolder; + if (convertView == null) { + convertView = LayoutInflater.from(context).inflate(R.layout.transfer_li_item, parent, false); + mHolder = new ViewHolder(convertView); + convertView.setTag(mHolder); + } else { + mHolder = (ViewHolder) convertView.getTag(); + } + + mHolder.happyNum.setText((String) data.get(position).get("happy")); + + if (StringUtil.isEmpty((String) data.get(position).get("quantity"))) { + //如果 quantity 没有值, 就 隐藏quantity这行所属的 LinearLayout + mHolder.transferQuantityLinear.setVisibility(View.GONE); + } else { + mHolder.transferQuantity.setText((String) data.get(position).get("quantity")); + } + + mHolder.transferTotal.setText((String) data.get(position).get("amount")); + + return convertView; + } + + class ViewHolder { + @InjectView(R.id.happy_Num) + TextView happyNum; + @InjectView(R.id.transfer_quantity) + TextView transferQuantity; + @InjectView(R.id.transfer_quantity_linear) + LinearLayout transferQuantityLinear; + @InjectView(R.id.transfer_total) + TextView transferTotal; + + ViewHolder(View view) { + ButterKnife.inject(this, view); + } + } + + @Override + public int getCount() { + return data.size(); + } + + @Override + public Object getItem(int position) { + return data.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + +} diff --git a/app/src/main/java/swipelistview/yjn/com/swiplistview/base/BaseActivity.java b/app/src/main/java/swipelistview/yjn/com/swiplistview/base/BaseActivity.java new file mode 100644 index 0000000..1f061cc --- /dev/null +++ b/app/src/main/java/swipelistview/yjn/com/swiplistview/base/BaseActivity.java @@ -0,0 +1,32 @@ +package swipelistview.yjn.com.swiplistview.base; + +import android.app.Activity; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; + +import swipelistview.yjn.com.swiplistview.widget.ToolbarWidget; + +/** + * Created by 0027006362 [liu.tong33@zte.com.cn] + * Date: 2016/3/8 + * Time: 11:04 + */ +public class BaseActivity extends AppCompatActivity { + + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + public void setBackListener(Activity context,ToolbarWidget toolbar) { + final Activity mContext = context; + if(toolbar != null){ + toolbar.setNavBtnClickListener(new ToolbarWidget.ToolbarBtnOnclickListener() { + @Override + public void onClick(View v) { + mContext.onBackPressed(); + } + }); + } + } +} diff --git a/app/src/main/java/swipelistview/yjn/com/swiplistview/ui/MainActivity.java b/app/src/main/java/swipelistview/yjn/com/swiplistview/ui/MainActivity.java new file mode 100644 index 0000000..5175259 --- /dev/null +++ b/app/src/main/java/swipelistview/yjn/com/swiplistview/ui/MainActivity.java @@ -0,0 +1,127 @@ +package swipelistview.yjn.com.swiplistview.ui; + +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.util.TypedValue; +import android.view.View; +import android.widget.TextView; + +import com.yjn.swipelistview.swipelistviewlibrary.widget.SwipeMenu; +import com.yjn.swipelistview.swipelistviewlibrary.widget.SwipeMenuCreator; +import com.yjn.swipelistview.swipelistviewlibrary.widget.SwipeMenuItem; +import com.yjn.swipelistview.swipelistviewlibrary.widget.SwipeMenuListView; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import butterknife.ButterKnife; +import butterknife.InjectView; +import butterknife.OnClick; +import swipelistview.yjn.com.swiplistview.R; +import swipelistview.yjn.com.swiplistview.adapter.TransferAdapter; +import swipelistview.yjn.com.swiplistview.base.BaseActivity; +import swipelistview.yjn.com.swiplistview.widget.ToolbarWidget; + +/** + * Description: + * Author: 0027008122 [yang.jianan@zte.com.cn] + * Time: 2016/3/31 14:18 + * Version: 1.0 + */ +public class MainActivity extends BaseActivity { + + @InjectView(R.id.transfer_title) + ToolbarWidget transferTitle; + @InjectView(R.id.rechage_amount_tv) + TextView rechageAmountTv; + @InjectView(R.id.recharge_count_tv) + TextView rechargeCountTv; + @InjectView(R.id.list_view) + SwipeMenuListView listView; + + //listview 数据 + List> listViewData; + //listview 假数据 + List> localTestData; + + List> mAppList; + + private TransferAdapter transferAdapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.transfer); + ButterKnife.inject(this); + setBackListener(this, transferTitle); + + initData(); + + } + + private void initData() { + + localTestData = new ArrayList<>(); + + for (int i = 0; i < 10; i++) { + HashMap testData = new HashMap<>(); + testData.put("happy", "happty" + i); + if (i % 2 == 0) { + testData.put("quantity", "15" + i); + } + testData.put("amount", "$" + "610" + i); + localTestData.add(testData); + } + + transferAdapter = new TransferAdapter(MainActivity.this, localTestData); + listView.setAdapter(transferAdapter); + + final SwipeMenuCreator creator = new SwipeMenuCreator() { + @Override + public void create(SwipeMenu menu) { + + // create "delete" item + SwipeMenuItem deleteItem = new SwipeMenuItem( + getApplicationContext()); + deleteItem.setBackground(new ColorDrawable(Color.parseColor("#fe3c3a"))); + deleteItem.setWidth(dp2px(89)); + deleteItem.setTitle("Delete"); + deleteItem.setTitleColor(Color.WHITE); + deleteItem.setTitleSize(20); + menu.addMenuItem(deleteItem); + } + }; + // set creator + listView.setMenuCreator(creator); + + // listener item click event + listView.setOnMenuItemClickListener(new SwipeMenuListView.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(int position, SwipeMenu menu, int index) { + if (index == 0) { + // delete + localTestData.remove(position); + transferAdapter.notifyDataSetChanged(); + } + return false; + } + }); + } + + private int dp2px(int dp) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, + this.getResources().getDisplayMetrics()); + } + + @OnClick({R.id.rechage_amount_tv, R.id.recharge_count_tv}) + public void onClick(View view) { + switch (view.getId()) { + case R.id.rechage_amount_tv: + break; + case R.id.recharge_count_tv: + break; + } + } +} diff --git a/app/src/main/java/swipelistview/yjn/com/swiplistview/util/StringUtil.java b/app/src/main/java/swipelistview/yjn/com/swiplistview/util/StringUtil.java new file mode 100644 index 0000000..3d31f55 --- /dev/null +++ b/app/src/main/java/swipelistview/yjn/com/swiplistview/util/StringUtil.java @@ -0,0 +1,618 @@ +package swipelistview.yjn.com.swiplistview.util; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 字符串操作工具包 + * Author:0027004702 [shen.weijian@zte.com.cn] + * Date:2016-01-14 + * Time:00:36 + * Version:1.0 + * TaskId: + */ +public class StringUtil { + + private final static Pattern emailer = Pattern.compile("\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"); + + private final static Pattern IMG_URL = Pattern.compile(".*?(gif|jpeg|png|jpg|bmp)"); + + private final static Pattern URL = Pattern.compile("^(https|http)://.*?$(net|com|.com.cn|org|me|)"); + + public final static DecimalFormat GHCFormat = new DecimalFormat("##0.00"); + + public final static DecimalFormat DATA_FORMAT = new DecimalFormat("##0.00 GB"); + + private final static ThreadLocal dateFormater = new ThreadLocal() { + @Override + protected SimpleDateFormat initialValue() { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + } + }; + + private final static ThreadLocal dateFormater2 = new ThreadLocal() { + @Override + protected SimpleDateFormat initialValue() { + return new SimpleDateFormat("yyyy-MM-dd"); + } + }; + + /** + * 将字符串转位日期类型 + * + * @param sdate + * @return + */ + public static Date toDate(String sdate) { + return toDate(sdate, dateFormater.get()); + } + + public static Date toDate(String sdate, SimpleDateFormat dateFormater) { + try { + return dateFormater.parse(sdate); + } catch (ParseException e) { + return null; + } + } + + public static String getDateString(Date date) { + return dateFormater.get().format(date); + } + + public static String friendly_time2(String sdate) { + String res = ""; + if (isEmpty(sdate)) + return ""; + + String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"}; + String currentData = StringUtil.getDataTime("MM-dd"); + int currentDay = toInt(currentData.substring(3)); + int currentMoth = toInt(currentData.substring(0, 2)); + + int sMoth = toInt(sdate.substring(5, 7)); + int sDay = toInt(sdate.substring(8, 10)); + int sYear = toInt(sdate.substring(0, 4)); + Date dt = new Date(sYear, sMoth - 1, sDay - 1); + + if (sDay == currentDay && sMoth == currentMoth) { + res = "今天 / " + weekDays[getWeekOfDate(new Date())]; + } else if (sDay == currentDay + 1 && sMoth == currentMoth) { + res = "昨天 / " + weekDays[(getWeekOfDate(new Date()) + 6) % 7]; + } else { + if (sMoth < 10) { + res = "0"; + } + res += sMoth + "/"; + if (sDay < 10) { + res += "0"; + } + res += sDay + " / " + weekDays[getWeekOfDate(dt)]; + } + + return res; + } + + + /** + * 智能格式化 + */ + public static String friendly_time3(String sdate) { + String res = ""; + if (isEmpty(sdate)) + return ""; + + Date date = StringUtil.toDate(sdate); + if (date == null) + return sdate; + + SimpleDateFormat format = dateFormater2.get(); + + if (isToday(date.getTime())) { + format.applyPattern(isMorning(date.getTime()) ? "上午 hh:mm" : "下午 hh:mm"); + res = format.format(date); + } else if (isYesterday(date.getTime())) { + format.applyPattern(isMorning(date.getTime()) ? "昨天 上午 hh:mm" : "昨天 下午 hh:mm"); + res = format.format(date); + } else if (isCurrentYear(date.getTime())) { + format.applyPattern(isMorning(date.getTime()) ? "MM-dd 上午 hh:mm" : "MM-dd 下午 hh:mm"); + res = format.format(date); + } else { + format.applyPattern(isMorning(date.getTime()) ? "yyyy-MM-dd 上午 hh:mm" : "yyyy-MM-dd 下午 hh:mm"); + res = format.format(date); + } + return res; + } + + /** + * @return 判断一个时间是不是上午 + */ + public static boolean isMorning(long when) { + android.text.format.Time time = new android.text.format.Time(); + time.set(when); + + int hour = time.hour; + return (hour >= 0) && (hour < 12); + } + + public static boolean isAftermoon(long when) { + android.text.format.Time time = new android.text.format.Time(); + time.set(when); + + int hour = time.hour; + return (hour >= 12) && (hour < 18); + } + + public static boolean isNight(long when) { + android.text.format.Time time = new android.text.format.Time(); + time.set(when); + + int hour = time.hour; + return (hour >= 18) && (hour < 24); + } + + /** + * @return 判断一个时间是不是今天 + */ + public static boolean isToday(long when) { + android.text.format.Time time = new android.text.format.Time(); + time.set(when); + + int thenYear = time.year; + int thenMonth = time.month; + int thenMonthDay = time.monthDay; + + time.set(System.currentTimeMillis()); + return (thenYear == time.year) + && (thenMonth == time.month) + && (thenMonthDay == time.monthDay); + } + + /** + * @return 判断一个时间是不是昨天 + */ + public static boolean isYesterday(long when) { + android.text.format.Time time = new android.text.format.Time(); + time.set(when); + + int thenYear = time.year; + int thenMonth = time.month; + int thenMonthDay = time.monthDay; + + time.set(System.currentTimeMillis()); + return (thenYear == time.year) + && (thenMonth == time.month) + && (time.monthDay - thenMonthDay == 1); + } + + /** + * @return 判断一个时间是不是今年 + */ + public static boolean isCurrentYear(long when) { + android.text.format.Time time = new android.text.format.Time(); + time.set(when); + + int thenYear = time.year; + + time.set(System.currentTimeMillis()); + return (thenYear == time.year); + } + + /** + * 获取当前日期是星期几
+ * + * @param dt + * @return 当前日期是星期几 + */ + public static int getWeekOfDate(Date dt) { + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + int w = cal.get(Calendar.DAY_OF_WEEK) - 1; + if (w < 0) + w = 0; + return w; + } + + /** + * 判断给定字符串时间是否为今日 + * + * @param sdate + * @return boolean + */ + public static boolean isToday(String sdate) { + boolean b = false; + Date time = toDate(sdate); + Date today = new Date(); + if (time != null) { + String nowDate = dateFormater2.get().format(today); + String timeDate = dateFormater2.get().format(time); + if (nowDate.equals(timeDate)) { + b = true; + } + } + return b; + } + + /** + * 返回long类型的今天的日期 + * + * @return + */ + public static long getToday() { + Calendar cal = Calendar.getInstance(); + String curDate = dateFormater2.get().format(cal.getTime()); + curDate = curDate.replace("-", ""); + return Long.parseLong(curDate); + } + + public static String getCurTimeStr() { + Calendar cal = Calendar.getInstance(); + String curDate = dateFormater.get().format(cal.getTime()); + return curDate; + } + + /*** + * 计算两个时间差,返回的是的秒s + * + * @param dete1 + * @param date2 + * @return + * @author 火蚁 2015-2-9 下午4:50:06 + */ + public static long calDateDifferent(String dete1, String date2) { + + long diff = 0; + + Date d1 = null; + Date d2 = null; + + try { + d1 = dateFormater.get().parse(dete1); + d2 = dateFormater.get().parse(date2); + + // 毫秒ms + diff = d2.getTime() - d1.getTime(); + + } catch (Exception e) { + e.printStackTrace(); + } + + return diff / 1000; + } + + /** + * 判断给定字符串是否空白串。 空白串是指由空格、制表符、回车符、换行符组成的字符串 若输入字符串为null或空字符串,返回true + * + * @param input + * @return boolean + */ + public static boolean isEmpty(String input) { + if (input == null || "".equals(input)) + return true; + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); + if (c != ' ' && c != '\t' && c != '\r' && c != '\n') { + return false; + } + } + return true; + } + + /** + * 判断是不是一个合法的电子邮件地址 + * + * @param email "" + * @return + */ + public static boolean isEmail(String email) { + if (email == null || email.trim().length() == 0) + return false; + return emailer.matcher(email).matches(); + } + + /** + * 验证是否是手机号码 + * + * @param str + * @return + */ + public static boolean isMobile(String str) { + Pattern pattern = Pattern.compile("1[0-9]{10}"); + Matcher matcher = pattern.matcher(str); + if (matcher.matches()) { + return true; + } else { + return false; + } + } + + /** + * 判断一个url是否为图片url + * + * @param url "" + * @return boolean + */ + public static boolean isImgUrl(String url) { + return !(url == null || url.trim().length() == 0) && IMG_URL.matcher(url).matches(); + } + + /** + * 判断是否为一个合法的url地址 + * + * @param str "" + * @return boolean + */ + public static boolean isUrl(String str) { + if (str == null || str.trim().length() == 0) + return false; + return URL.matcher(str).matches(); + } + + /** + * 字符串转整数 + * + * @param str "" + * @param defValue "" + * @return int + */ + public static int toInt(String str, int defValue) { + try { + return Integer.parseInt(str); + } catch (Exception ignored) { + } + return defValue; + } + + /** + * 对象转整数 + * + * @param obj "" + * @return 转换异常返回 0 + */ + public static int toInt(Object obj) { + if (obj == null) + return 0; + return toInt(obj.toString(), 0); + } + + /** + * 判断账号 是否为由 字母数字下划线 组成 + * + * @param firstChar "" + * @return 数字格式不正确 返回 false + */ + public static boolean isCustAccount(String firstChar) { + Pattern pattern = Pattern.compile("[0-9a-zA-Z _-]+$"); +// Pattern pattern = Pattern.compile("^[a-zA-Z0-9_]{1,}$"); + Matcher matcher = pattern.matcher(firstChar); + if (matcher.matches()) { + return true; + } + return false; + } + + /** + * 判断账号首字母 是否为非数字 + * + * @param str "" + * @return 首字母匹配异常(非数字) 返回 false + */ + public static boolean isNum(String str) { + try { + new BigDecimal(str); + return true; + } catch (Exception e) { + return false; + } + + } + + /** + * 对象转整数 + * + * @param obj "" + * @return 转换异常返回 0 + */ + public static long toLong(String obj) { + try { + return Long.parseLong(obj); + } catch (Exception ignored) { + } + return 0; + } + + /** + * 字符串转布尔值 + * + * @param b "" + * @return 转换异常返回 false + */ + public static boolean toBool(String b) { + try { + return Boolean.parseBoolean(b); + } catch (Exception ignored) { + } + return false; + } + + public static String getString(String s) { + return s == null ? "" : s; + } + + /** + * 将一个InputStream流转换成字符串 + * + * @param is "" + * @return String + */ + public static String toConvertString(InputStream is) { + StringBuffer res = new StringBuffer(); + InputStreamReader isr = new InputStreamReader(is); + BufferedReader read = new BufferedReader(isr); + try { + String line; + line = read.readLine(); + while (line != null) { + res.append(line).append("
"); + line = read.readLine(); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (null != isr) { + isr.close(); + isr.close(); + } + if (null != read) { + read.close(); + read = null; + } + if (null != is) { + is.close(); + is = null; + } + } catch (IOException ignored) { + } + } + return res.toString(); + } + + /*** + * 截取字符串 + * + * @param start 从那里开始,0算起 + * @param num 截取多少个 + * @param str 截取的字符串 + * @return String + */ + public static String getSubString(int start, int num, String str) { + if (str == null) { + return ""; + } + int leng = str.length(); + if (start < 0) { + start = 0; + } + if (start > leng) { + start = leng; + } + if (num < 0) { + num = 1; + } + int end = start + num; + if (end > leng) { + end = leng; + } + return str.substring(start, end); + } + + /** + * 获取当前时间为每年第几周 + * + * @return "" + */ + public static int getWeekOfYear() { + return getWeekOfYear(new Date()); + } + + /** + * 获取当前时间为每年第几周 + * + * @param date "" + * @return int + */ + public static int getWeekOfYear(Date date) { + Calendar c = Calendar.getInstance(); + c.setFirstDayOfWeek(Calendar.MONDAY); + c.setTime(date); + int week = c.get(Calendar.WEEK_OF_YEAR) - 1; + week = week == 0 ? 52 : week; + return week > 0 ? week : 1; + } + + public static int[] getCurrentDate() { + int[] dateBundle = new int[3]; + String[] temp = getDataTime("yyyy-MM-dd").split("-"); + + for (int i = 0; i < 3; i++) { + try { + dateBundle[i] = Integer.parseInt(temp[i]); + } catch (Exception e) { + dateBundle[i] = 0; + } + } + return dateBundle; + } + + /** + * 返回当前系统时间 + */ + public static String getDataTime(String format) { + SimpleDateFormat df = new SimpleDateFormat(format); + return df.format(new Date()); + } + + /** + * 转百分比 保留两位小数 + * + * @param p1 + * @param p2 + * @return + */ + public static String percent(double p1, double p2) { + String str; + double p3 = p1 / p2; + NumberFormat nf = NumberFormat.getPercentInstance(); + nf.setMinimumFractionDigits(2); + str = nf.format(p3); + return str; + } + + /** + * 转百分比 保留整数 + * + * @param p1 + * @param p2 + * @return + */ + public static String percent2(double p1, double p2) { + String str; + double p3 = p1 / p2; + NumberFormat nf = NumberFormat.getPercentInstance(); + nf.setMinimumFractionDigits(0); + str = nf.format(p3); + return str; + } + + public static int percent2Number(double p1, double p2) { + + if (p2 == 0) + return 0; + + Number number = 0; + NumberFormat nf = NumberFormat.getPercentInstance(); + try { + number = nf.parse(percent2(p1 * 100, p2)); + } catch (ParseException e) { + e.printStackTrace(); + } + return number.intValue(); + } + + public static float parseMoney(String mstr) { + Float money = (isEmpty(mstr) ? 0 : Float.valueOf(mstr)); + return money; + } +} diff --git a/app/src/main/java/swipelistview/yjn/com/swiplistview/widget/ToolbarWidget.java b/app/src/main/java/swipelistview/yjn/com/swiplistview/widget/ToolbarWidget.java new file mode 100644 index 0000000..84d4d6e --- /dev/null +++ b/app/src/main/java/swipelistview/yjn/com/swiplistview/widget/ToolbarWidget.java @@ -0,0 +1,146 @@ +package swipelistview.yjn.com.swiplistview.widget; + + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.support.v7.widget.Toolbar; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageButton; +import android.widget.TextView; + +import butterknife.ButterKnife; +import butterknife.InjectView; +import butterknife.OnClick; +import swipelistview.yjn.com.swiplistview.R; + +/** + * Description: 自定义 toolbar + * Author 0027004702. + * Time:16/1/26 16:53 + * Version:1.0 + * Task: + */ +public class ToolbarWidget extends Toolbar { + + private Context context; + + private ToolbarBtnOnclickListener listener; + + private ToolbarMenuOnclickListener menuOnclickListener; + + // TODO 从属性配置文件中获取 + private int mTitleMarginTop; + + private int mTitleMarginBottom; + + private int mTitleMarginStart; + + private int mTitleMarginEnd; + + // TODO navigation icon 这里其实不应该仅仅是显示或不显示后退键 + private static final Class superView = ToolbarWidget.class.getSuperclass(); + + @InjectView(R.id.widget_toolbar_title) + TextView mTitleTextView; + + @InjectView(R.id.widget_toolbar_subtitle) + TextView mSubtitleTextView; + + @InjectView(R.id.toolbar_l_nav) + ImageButton leftNavBtn; + + @InjectView((R.id.toolbar_r_nav)) + ImageButton rightNavBtn; + + public ToolbarWidget(Context context) { + this(context, null); + } + + public ToolbarWidget(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ToolbarWidget(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + this.context = context; + + View view = LayoutInflater.from(context).inflate(R.layout.widget_toolbar, this); + + ButterKnife.inject(this, view); + + initView(attrs, defStyleAttr); + + } + + private void initView(AttributeSet attrs, int defStyleAttr) { + + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.toolbarWidget); + + Drawable lNavIcon = ta.getDrawable(R.styleable.toolbarWidget_leftnav); + if (lNavIcon != null) { +// leftNavBtn.setBackgroundDrawable(lNavIcon); + + leftNavBtn.setImageDrawable(lNavIcon); + leftNavBtn.setVisibility(VISIBLE); + } + + Drawable rNavIcon = ta.getDrawable(R.styleable.toolbarWidget_rightnav); + if (rNavIcon != null) { + rightNavBtn.setBackgroundDrawable(rNavIcon); + rightNavBtn.setVisibility(VISIBLE); + } + + final CharSequence title = ta.getText(R.styleable.toolbarWidget_title); + if (!TextUtils.isEmpty(title)) { + mTitleTextView.setText(title); + } + + if (ta.hasValue(R.styleable.toolbarWidget_titlecolor)) { + mTitleTextView.setTextColor(ta.getColor(R.styleable.toolbarWidget_titlecolor, 0xffffffff)); + } + + + // TODO subtitle + + } + + @OnClick(R.id.toolbar_l_nav) + void leftNavBtnOnclick() { + this.listener.onClick(leftNavBtn); + } + + @OnClick(R.id.toolbar_r_nav) + void rightNavBtnOnClick() { + this.menuOnclickListener.menuOnclick(rightNavBtn); + } + + public void setNavBtnClickListener(ToolbarBtnOnclickListener listener) { + this.listener = listener; + } + + public void setMenuOnclickListener(ToolbarMenuOnclickListener listener) { + this.menuOnclickListener = listener; + } + + @Override + public void setSubtitle(CharSequence subtitle) { + mSubtitleTextView.setVisibility(View.VISIBLE); + mSubtitleTextView.setText(subtitle); + super.setSubtitle(subtitle); + } + + public interface ToolbarBtnOnclickListener { + void onClick(View v); + } + + public interface ToolbarMenuOnclickListener { + void menuOnclick(View v); + } + + +} diff --git a/app/src/main/res/drawable-xhdpi/toolbar_left_back.png b/app/src/main/res/drawable-xhdpi/toolbar_left_back.png new file mode 100644 index 0000000..005ec15 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/toolbar_left_back.png differ diff --git a/app/src/main/res/drawable-xhdpi/transfer_icon.png b/app/src/main/res/drawable-xhdpi/transfer_icon.png new file mode 100644 index 0000000..1aa70ba Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/transfer_icon.png differ diff --git a/app/src/main/res/drawable/common_btn_normal.xml b/app/src/main/res/drawable/common_btn_normal.xml new file mode 100644 index 0000000..1e64052 --- /dev/null +++ b/app/src/main/res/drawable/common_btn_normal.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/common_btn_pressed.xml b/app/src/main/res/drawable/common_btn_pressed.xml new file mode 100644 index 0000000..ab72556 --- /dev/null +++ b/app/src/main/res/drawable/common_btn_pressed.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/common_btn_selector.xml b/app/src/main/res/drawable/common_btn_selector.xml new file mode 100644 index 0000000..2a49ee6 --- /dev/null +++ b/app/src/main/res/drawable/common_btn_selector.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/switcher_active_btn_bkg.xml b/app/src/main/res/drawable/switcher_active_btn_bkg.xml new file mode 100644 index 0000000..d0c7f5a --- /dev/null +++ b/app/src/main/res/drawable/switcher_active_btn_bkg.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/transfer.xml b/app/src/main/res/layout/transfer.xml new file mode 100644 index 0000000..d8b2b73 --- /dev/null +++ b/app/src/main/res/layout/transfer.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/transfer_li_item.xml b/app/src/main/res/layout/transfer_li_item.xml new file mode 100644 index 0000000..d12f628 --- /dev/null +++ b/app/src/main/res/layout/transfer_li_item.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/widget_toolbar.xml b/app/src/main/res/layout/widget_toolbar.xml new file mode 100644 index 0000000..a9fa9be --- /dev/null +++ b/app/src/main/res/layout/widget_toolbar.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..cde69bc Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..c133a0c Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..bfa42f0 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..324e72c Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..aee44e1 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 0000000..63fc816 --- /dev/null +++ b/app/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ + + + 64dp + diff --git a/app/src/main/res/values/attr.xml b/app/src/main/res/values/attr.xml new file mode 100644 index 0000000..bba2d0d --- /dev/null +++ b/app/src/main/res/values/attr.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..2b8be60 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,43 @@ + + + #3F51B5 + #303F9F + #FF4081 + + + #40FFFFFF + #FFFFFF + #000000 + #808080 + #FF0000 + #FFD700 + #FFFF00 + #008000 + #800080 + #FFC0CB + #FFA500 + #FFFACD + #F5F5F5 + #708090 + #0083FF + + #ea5a0e + + #ed4233 + #999999 + + #c1c1c1 + + + #313131 + #707070 + + + #707070 + #f0eff5 + + #dedede + + + #f0eff5 + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..21d6f7d --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,8 @@ + + + 16dp + 16dp + + 19sp + 18sp + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..da8a0e0 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + SwipListView + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..11c5ba6 --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + diff --git a/app/src/test/java/swipelistview/yjn/com/swiplistview/ExampleUnitTest.java b/app/src/test/java/swipelistview/yjn/com/swiplistview/ExampleUnitTest.java new file mode 100644 index 0000000..280921b --- /dev/null +++ b/app/src/test/java/swipelistview/yjn/com/swiplistview/ExampleUnitTest.java @@ -0,0 +1,15 @@ +package swipelistview.yjn.com.swiplistview; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * To work on unit tests, switch the Test Artifact in the Build Variants view. + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..d7c2c93 --- /dev/null +++ b/build.gradle @@ -0,0 +1,26 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:2.0.0' + + /*// https://bintray.com + classpath 'com.novoda:bintray-release:0.3.4'*/ + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..1d3591c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,18 @@ +# 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. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# 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 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..13372ae Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..122a0dc --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Dec 28 10:00:20 PST 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..9d82f78 --- /dev/null +++ b/gradlew @@ -0,0 +1,160 @@ +#!/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 "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..8a0b282 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@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 diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..3fb6e70 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':app', ':swipelistviewlibrary' diff --git a/swipelistviewlibrary/.gitignore b/swipelistviewlibrary/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/swipelistviewlibrary/.gitignore @@ -0,0 +1 @@ +/build diff --git a/swipelistviewlibrary/build.gradle b/swipelistviewlibrary/build.gradle new file mode 100644 index 0000000..8801459 --- /dev/null +++ b/swipelistviewlibrary/build.gradle @@ -0,0 +1,34 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.3" + + defaultConfig { + minSdkVersion 15 + targetSdkVersion 23 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + testCompile 'junit:junit:4.12' + compile 'com.android.support:appcompat-v7:23.3.0' +} + +/*publish { + userOrg = 'yangxiaoge' //bintray.com用户名 + groupId = 'com.yjn' //jcenter上的路径 + artifacts = 'SwipeListViewLibrary' //项目名称 + publishVersion = '1.0.0' //版本号 + desc = 'hey, guays. This is my first repository. ' //描述,不重要 + website = 'https://github.com/yangxiaoge/SwipeListView'//网站,不重要 +}*/ diff --git a/swipelistviewlibrary/proguard-rules.pro b/swipelistviewlibrary/proguard-rules.pro new file mode 100644 index 0000000..d7adfc4 --- /dev/null +++ b/swipelistviewlibrary/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in F:\ZTEsoft\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 *; +#} diff --git a/swipelistviewlibrary/src/androidTest/java/com/yjn/swipelistview/swipelistviewlibrary/ApplicationTest.java b/swipelistviewlibrary/src/androidTest/java/com/yjn/swipelistview/swipelistviewlibrary/ApplicationTest.java new file mode 100644 index 0000000..0e535c0 --- /dev/null +++ b/swipelistviewlibrary/src/androidTest/java/com/yjn/swipelistview/swipelistviewlibrary/ApplicationTest.java @@ -0,0 +1,13 @@ +package com.yjn.swipelistview.swipelistviewlibrary; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/swipelistviewlibrary/src/main/AndroidManifest.xml b/swipelistviewlibrary/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c7fe518 --- /dev/null +++ b/swipelistviewlibrary/src/main/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/BaseSwipListAdapter.java b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/BaseSwipListAdapter.java new file mode 100644 index 0000000..2a56493 --- /dev/null +++ b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/BaseSwipListAdapter.java @@ -0,0 +1,41 @@ +/* +* The MIT License (MIT) +* +* Copyright (c) 2015 nimengbo +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ +package com.yjn.swipelistview.swipelistviewlibrary.widget; + +import android.widget.BaseAdapter; + +/** + * Created by Abner on 15/11/20. + * Email nimengbo@gmail.com + * github https://github.com/nimengbo + */ +public abstract class BaseSwipListAdapter extends BaseAdapter { + + public boolean getSwipEnableByPosition(int position){ + return true; + } + + + +} diff --git a/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenu.java b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenu.java new file mode 100644 index 0000000..cecdd5a --- /dev/null +++ b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenu.java @@ -0,0 +1,53 @@ +package com.yjn.swipelistview.swipelistviewlibrary.widget; + +import android.content.Context; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author baoyz + * @date 2014-8-23 + * + */ +public class SwipeMenu { + + private Context mContext; + private List mItems; + private int mViewType; + + public SwipeMenu(Context context) { + mContext = context; + mItems = new ArrayList(); + } + + public Context getContext() { + return mContext; + } + + public void addMenuItem(SwipeMenuItem item) { + mItems.add(item); + } + + public void removeMenuItem(SwipeMenuItem item) { + mItems.remove(item); + } + + public List getMenuItems() { + return mItems; + } + + public SwipeMenuItem getMenuItem(int index) { + return mItems.get(index); + } + + public int getViewType() { + return mViewType; + } + + public void setViewType(int viewType) { + this.mViewType = viewType; + } + +} diff --git a/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuAdapter.java b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuAdapter.java new file mode 100644 index 0000000..2adc947 --- /dev/null +++ b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuAdapter.java @@ -0,0 +1,148 @@ +package com.yjn.swipelistview.swipelistviewlibrary.widget; + +import android.content.Context; +import android.database.DataSetObserver; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListAdapter; +import android.widget.WrapperListAdapter; + +/** + * + * @author baoyz + * @date 2014-8-24 + * + */ +public class SwipeMenuAdapter implements WrapperListAdapter, + SwipeMenuView.OnSwipeItemClickListener { + + private ListAdapter mAdapter; + private Context mContext; + private SwipeMenuListView.OnMenuItemClickListener onMenuItemClickListener; + + public SwipeMenuAdapter(Context context, ListAdapter adapter) { + mAdapter = adapter; + mContext = context; + } + + @Override + public int getCount() { + return mAdapter.getCount(); + } + + @Override + public Object getItem(int position) { + return mAdapter.getItem(position); + } + + @Override + public long getItemId(int position) { + return mAdapter.getItemId(position); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + SwipeMenuLayout layout = null; + if (convertView == null) { + View contentView = mAdapter.getView(position, convertView, parent); + SwipeMenu menu = new SwipeMenu(mContext); + menu.setViewType(getItemViewType(position)); + createMenu(menu); + SwipeMenuView menuView = new SwipeMenuView(menu, + (SwipeMenuListView) parent); + menuView.setOnSwipeItemClickListener(this); + SwipeMenuListView listView = (SwipeMenuListView) parent; + layout = new SwipeMenuLayout(contentView, menuView, + listView.getCloseInterpolator(), + listView.getOpenInterpolator()); + layout.setPosition(position); + } else { + layout = (SwipeMenuLayout) convertView; + layout.closeMenu(); + layout.setPosition(position); + View view = mAdapter.getView(position, layout.getContentView(), + parent); + } + if (mAdapter instanceof BaseSwipListAdapter) { + boolean swipEnable = (((BaseSwipListAdapter) mAdapter).getSwipEnableByPosition(position)); + layout.setSwipEnable(swipEnable); + } + return layout; + } + + public void createMenu(SwipeMenu menu) { + // Test Code + SwipeMenuItem item = new SwipeMenuItem(mContext); + item.setTitle("Item 1"); + item.setBackground(new ColorDrawable(Color.GRAY)); + item.setWidth(300); + menu.addMenuItem(item); + + item = new SwipeMenuItem(mContext); + item.setTitle("Item 2"); + item.setBackground(new ColorDrawable(Color.RED)); + item.setWidth(300); + menu.addMenuItem(item); + } + + @Override + public void onItemClick(SwipeMenuView view, SwipeMenu menu, int index) { + if (onMenuItemClickListener != null) { + onMenuItemClickListener.onMenuItemClick(view.getPosition(), menu, + index); + } + } + + public void setOnSwipeItemClickListener( + SwipeMenuListView.OnMenuItemClickListener onMenuItemClickListener) { + this.onMenuItemClickListener = onMenuItemClickListener; + } + + @Override + public void registerDataSetObserver(DataSetObserver observer) { + mAdapter.registerDataSetObserver(observer); + } + + @Override + public void unregisterDataSetObserver(DataSetObserver observer) { + mAdapter.unregisterDataSetObserver(observer); + } + + @Override + public boolean areAllItemsEnabled() { + return mAdapter.areAllItemsEnabled(); + } + + @Override + public boolean isEnabled(int position) { + return mAdapter.isEnabled(position); + } + + @Override + public boolean hasStableIds() { + return mAdapter.hasStableIds(); + } + + @Override + public int getItemViewType(int position) { + return mAdapter.getItemViewType(position); + } + + @Override + public int getViewTypeCount() { + return mAdapter.getViewTypeCount(); + } + + @Override + public boolean isEmpty() { + return mAdapter.isEmpty(); + } + + @Override + public ListAdapter getWrappedAdapter() { + return mAdapter; + } + +} diff --git a/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuCreator.java b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuCreator.java new file mode 100644 index 0000000..1d6c6d2 --- /dev/null +++ b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuCreator.java @@ -0,0 +1,13 @@ +package com.yjn.swipelistview.swipelistviewlibrary.widget; + + +/** + * + * @author baoyz + * @date 2014-8-24 + * + */ +public interface SwipeMenuCreator { + + void create(SwipeMenu menu); +} diff --git a/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuItem.java b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuItem.java new file mode 100644 index 0000000..7acf99d --- /dev/null +++ b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuItem.java @@ -0,0 +1,96 @@ +package com.yjn.swipelistview.swipelistviewlibrary.widget; + + +import android.content.Context; +import android.graphics.drawable.Drawable; + +/** + * + * @author baoyz + * @date 2014-8-23 + * + */ +public class SwipeMenuItem { + + private int id; + private Context mContext; + private String title; + private Drawable icon; + private Drawable background; + private int titleColor; + private int titleSize; + private int width; + + public SwipeMenuItem(Context context) { + mContext = context; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getTitleColor() { + return titleColor; + } + + public int getTitleSize() { + return titleSize; + } + + public void setTitleSize(int titleSize) { + this.titleSize = titleSize; + } + + public void setTitleColor(int titleColor) { + this.titleColor = titleColor; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setTitle(int resId) { + setTitle(mContext.getString(resId)); + } + + public Drawable getIcon() { + return icon; + } + + public void setIcon(Drawable icon) { + this.icon = icon; + } + + public void setIcon(int resId) { + this.icon = mContext.getResources().getDrawable(resId); + } + + public Drawable getBackground() { + return background; + } + + public void setBackground(Drawable background) { + this.background = background; + } + + public void setBackground(int resId) { + this.background = mContext.getResources().getDrawable(resId); + } + + public int getWidth() { + return width; + } + + public void setWidth(int width) { + this.width = width; + } + +} diff --git a/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuLayout.java b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuLayout.java new file mode 100644 index 0000000..80e3936 --- /dev/null +++ b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuLayout.java @@ -0,0 +1,362 @@ +package com.yjn.swipelistview.swipelistviewlibrary.widget; + +import android.content.Context; +import android.support.v4.view.GestureDetectorCompat; +import android.support.v4.widget.ScrollerCompat; +import android.util.AttributeSet; +import android.util.Log; +import android.util.TypedValue; +import android.view.GestureDetector.OnGestureListener; +import android.view.GestureDetector.SimpleOnGestureListener; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.Interpolator; +import android.widget.AbsListView; +import android.widget.FrameLayout; + +/** + * + * @author baoyz + * @date 2014-8-23 + * + */ +public class SwipeMenuLayout extends FrameLayout { + + private static final int CONTENT_VIEW_ID = 1; + private static final int MENU_VIEW_ID = 2; + + private static final int STATE_CLOSE = 0; + private static final int STATE_OPEN = 1; + + private int mSwipeDirection; + + private View mContentView; + private SwipeMenuView mMenuView; + private int mDownX; + private int state = STATE_CLOSE; + private GestureDetectorCompat mGestureDetector; + private OnGestureListener mGestureListener; + private boolean isFling; + private int MIN_FLING = dp2px(15); + private int MAX_VELOCITYX = -dp2px(500); + private ScrollerCompat mOpenScroller; + private ScrollerCompat mCloseScroller; + private int mBaseX; + private int position; + private Interpolator mCloseInterpolator; + private Interpolator mOpenInterpolator; + + private boolean mSwipEnable = true; + + public SwipeMenuLayout(View contentView, SwipeMenuView menuView) { + this(contentView, menuView, null, null); + } + + public SwipeMenuLayout(View contentView, SwipeMenuView menuView, + Interpolator closeInterpolator, Interpolator openInterpolator) { + super(contentView.getContext()); + mCloseInterpolator = closeInterpolator; + mOpenInterpolator = openInterpolator; + mContentView = contentView; + mMenuView = menuView; + mMenuView.setLayout(this); + init(); + } + + // private SwipeMenuLayout(Context context, AttributeSet attrs, int + // defStyle) { + // super(context, attrs, defStyle); + // } + + private SwipeMenuLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + private SwipeMenuLayout(Context context) { + super(context); + } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + mMenuView.setPosition(position); + } + + public void setSwipeDirection(int swipeDirection) { + mSwipeDirection = swipeDirection; + } + + private void init() { + setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT)); + mGestureListener = new SimpleOnGestureListener() { + @Override + public boolean onDown(MotionEvent e) { + isFling = false; + return true; + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, + float velocityX, float velocityY) { + // TODO + if (Math.abs(e1.getX() - e2.getX()) > MIN_FLING + && velocityX < MAX_VELOCITYX) { + isFling = true; + } + // Log.i("byz", MAX_VELOCITYX + ", velocityX = " + velocityX); + return super.onFling(e1, e2, velocityX, velocityY); + } + }; + mGestureDetector = new GestureDetectorCompat(getContext(), + mGestureListener); + + // mScroller = ScrollerCompat.create(getContext(), new + // BounceInterpolator()); + if (mCloseInterpolator != null) { + mCloseScroller = ScrollerCompat.create(getContext(), + mCloseInterpolator); + } else { + mCloseScroller = ScrollerCompat.create(getContext()); + } + if (mOpenInterpolator != null) { + mOpenScroller = ScrollerCompat.create(getContext(), + mOpenInterpolator); + } else { + mOpenScroller = ScrollerCompat.create(getContext()); + } + + LayoutParams contentParams = new LayoutParams( + LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + mContentView.setLayoutParams(contentParams); + if (mContentView.getId() < 1) { + mContentView.setId(CONTENT_VIEW_ID); + } + + mMenuView.setId(MENU_VIEW_ID); + mMenuView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT)); + + addView(mContentView); + addView(mMenuView); + + // if (mContentView.getBackground() == null) { + // mContentView.setBackgroundColor(Color.WHITE); + // } + + // in android 2.x, MenuView height is MATCH_PARENT is not work. + // getViewTreeObserver().addOnGlobalLayoutListener( + // new OnGlobalLayoutListener() { + // @Override + // public void onGlobalLayout() { + // setMenuHeight(mContentView.getHeight()); + // // getViewTreeObserver() + // // .removeGlobalOnLayoutListener(this); + // } + // }); + + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + } + + public boolean onSwipe(MotionEvent event) { + mGestureDetector.onTouchEvent(event); + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + mDownX = (int) event.getX(); + isFling = false; + break; + case MotionEvent.ACTION_MOVE: + // Log.i("byz", "downX = " + mDownX + ", moveX = " + event.getX()); + int dis = (int) (mDownX - event.getX()); + if (state == STATE_OPEN) { + dis += mMenuView.getWidth()*mSwipeDirection;; + } + swipe(dis); + break; + // add by liutong start + // 当 listview 处于 有 父 view 的 时候 滑动 有时候 会 触发 cancel 事件 + case MotionEvent.ACTION_CANCEL: + if ((isFling || Math.abs(mDownX - event.getX()) > (mMenuView.getWidth() / 4)) && + Math.signum(mDownX - event.getX()) == mSwipeDirection) { + // open + smoothOpenMenu(); + } + else { + // close + smoothCloseMenu(); + return false; + } + break; + // add by liutong end + case MotionEvent.ACTION_UP: + if ((isFling || Math.abs(mDownX - event.getX()) > (mMenuView.getWidth() / 2)) && + Math.signum(mDownX - event.getX()) == mSwipeDirection) { + // open + smoothOpenMenu(); + } else { + // close + smoothCloseMenu(); + return false; + } + break; + } + return true; + } + + public boolean isOpen() { + return state == STATE_OPEN; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return super.onTouchEvent(event); + } + + private void swipe(int dis) { + if(!mSwipEnable){ + return ; + } + if (Math.signum(dis) != mSwipeDirection) { + dis = 0; + } else if (Math.abs(dis) > mMenuView.getWidth()) { + dis = mMenuView.getWidth()*mSwipeDirection; + } + + mContentView.layout(-dis, mContentView.getTop(), + mContentView.getWidth() -dis, getMeasuredHeight()); + + if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) { + + mMenuView.layout(mContentView.getWidth() - dis, mMenuView.getTop(), + mContentView.getWidth() + mMenuView.getWidth() - dis, + mMenuView.getBottom()); + } else { + mMenuView.layout(-mMenuView.getWidth() - dis, mMenuView.getTop(), + - dis, mMenuView.getBottom()); + } + } + + @Override + public void computeScroll() { + if (state == STATE_OPEN) { + if (mOpenScroller.computeScrollOffset()) { + swipe(mOpenScroller.getCurrX()*mSwipeDirection); + postInvalidate(); + } + } else { + if (mCloseScroller.computeScrollOffset()) { + swipe((mBaseX - mCloseScroller.getCurrX())*mSwipeDirection); + postInvalidate(); + } + } + } + + public void smoothCloseMenu() { + state = STATE_CLOSE; + if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) { + mBaseX = -mContentView.getLeft(); + mCloseScroller.startScroll(0, 0, mMenuView.getWidth(), 0, 350); + } else { + mBaseX = mMenuView.getRight(); + mCloseScroller.startScroll(0, 0, mMenuView.getWidth(), 0, 350); + } + postInvalidate(); + } + + public void smoothOpenMenu() { + if(!mSwipEnable){ + return ; + } + state = STATE_OPEN; + if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) { + mOpenScroller.startScroll(-mContentView.getLeft(), 0, mMenuView.getWidth(), 0, 350); + } else { + mOpenScroller.startScroll(mContentView.getLeft(), 0, mMenuView.getWidth(), 0, 350); + } + postInvalidate(); + } + + public void closeMenu() { + if (mCloseScroller.computeScrollOffset()) { + mCloseScroller.abortAnimation(); + } + if (state == STATE_OPEN) { + state = STATE_CLOSE; + swipe(0); + } + } + + public void openMenu() { + if(!mSwipEnable){ + return ; + } + if (state == STATE_CLOSE) { + state = STATE_OPEN; + swipe(mMenuView.getWidth() * mSwipeDirection); + } + } + + public View getContentView() { + return mContentView; + } + + public SwipeMenuView getMenuView() { + return mMenuView; + } + + private int dp2px(int dp) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, + getContext().getResources().getDisplayMetrics()); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + mMenuView.measure(MeasureSpec.makeMeasureSpec(0, + MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec( + getMeasuredHeight(), MeasureSpec.EXACTLY)); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + mContentView.layout(0, 0, getMeasuredWidth(), + mContentView.getMeasuredHeight()); + if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) { + mMenuView.layout(getMeasuredWidth(), 0, + getMeasuredWidth() + mMenuView.getMeasuredWidth(), + mContentView.getMeasuredHeight()); + } else { + mMenuView.layout(-mMenuView.getMeasuredWidth(), 0, + 0, mContentView.getMeasuredHeight()); + } + } + + public void setMenuHeight(int measuredHeight) { + Log.i("byz", "pos = " + position + ", height = " + measuredHeight); + LayoutParams params = (LayoutParams) mMenuView.getLayoutParams(); + if (params.height != measuredHeight) { + params.height = measuredHeight; + mMenuView.setLayoutParams(mMenuView.getLayoutParams()); + } + } + + public void setSwipEnable(boolean swipEnable){ + mSwipEnable = swipEnable; + } + + public boolean getSwipEnable(){ + return mSwipEnable; + } +} diff --git a/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuListView.java b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuListView.java new file mode 100644 index 0000000..ffa71c4 --- /dev/null +++ b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuListView.java @@ -0,0 +1,374 @@ +package com.yjn.swipelistview.swipelistviewlibrary.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.Interpolator; +import android.widget.ListAdapter; +import android.widget.ListView; + +/** + * @author baoyz + * @date 2014-8-18 + */ +public class SwipeMenuListView extends ListView { + + private static final int TOUCH_STATE_NONE = 0; + private static final int TOUCH_STATE_X = 1; + private static final int TOUCH_STATE_Y = 2; + + public static final int DIRECTION_LEFT = 1; + public static final int DIRECTION_RIGHT = -1; + private int mDirection = 1;//swipe from right to left by default + + private int MAX_Y = 5; + private int MAX_X = 3; + private float mDownX; + private float mDownY; + private int mTouchState; + private int mTouchPosition; + private SwipeMenuLayout mTouchView; + private OnSwipeListener mOnSwipeListener; + + private SwipeMenuCreator mMenuCreator; + private OnMenuItemClickListener mOnMenuItemClickListener; + private OnMenuStateChangeListener mOnMenuStateChangeListener; + private Interpolator mCloseInterpolator; + private Interpolator mOpenInterpolator; + + public SwipeMenuListView(Context context) { + super(context); + init(); + } + + public SwipeMenuListView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + public SwipeMenuListView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + MAX_X = dp2px(MAX_X); + MAX_Y = dp2px(MAX_Y); + mTouchState = TOUCH_STATE_NONE; + } + + @Override + public void setAdapter(ListAdapter adapter) { + super.setAdapter(new SwipeMenuAdapter(getContext(), adapter) { + @Override + public void createMenu(SwipeMenu menu) { + if (mMenuCreator != null) { + mMenuCreator.create(menu); + } + } + + @Override + public void onItemClick(SwipeMenuView view, SwipeMenu menu, + int index) { + boolean flag = false; + if (mOnMenuItemClickListener != null) { + flag = mOnMenuItemClickListener.onMenuItemClick( + view.getPosition(), menu, index); + } + if (mTouchView != null && !flag) { + mTouchView.smoothCloseMenu(); + } + } + }); + } + + public void setCloseInterpolator(Interpolator interpolator) { + mCloseInterpolator = interpolator; + } + + public void setOpenInterpolator(Interpolator interpolator) { + mOpenInterpolator = interpolator; + } + + public Interpolator getOpenInterpolator() { + return mOpenInterpolator; + } + + public Interpolator getCloseInterpolator() { + return mCloseInterpolator; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + //在拦截处处理,在滑动设置了点击事件的地方也能swip,点击时又不能影响原来的点击事件 + int action = ev.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + mDownX = ev.getX(); + mDownY = ev.getY(); + boolean handled = super.onInterceptTouchEvent(ev); + mTouchState = TOUCH_STATE_NONE; + mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY()); + View view = getChildAt(mTouchPosition - getFirstVisiblePosition()); + + //只在空的时候赋值 以免每次触摸都赋值,会有多个open状态 + if (view instanceof SwipeMenuLayout) { + //如果有打开了 就拦截. + if (mTouchView != null && mTouchView.isOpen() && !inRangeOfView(mTouchView.getMenuView(), ev)) { + return true; + } + mTouchView = (SwipeMenuLayout) view; + mTouchView.setSwipeDirection(mDirection); + } + //如果摸在另外个view + if (mTouchView != null && mTouchView.isOpen() && view != mTouchView) { + handled = true; + } + + if (mTouchView != null) { + mTouchView.onSwipe(ev); + } + return handled; + case MotionEvent.ACTION_MOVE: + float dy = Math.abs((ev.getY() - mDownY)); + float dx = Math.abs((ev.getX() - mDownX)); + if (Math.abs(dy) > MAX_Y || Math.abs(dx) > MAX_X) { + //每次拦截的down都把触摸状态设置成了TOUCH_STATE_NONE 只有返回true才会走onTouchEvent 所以写在这里就够了 + if (mTouchState == TOUCH_STATE_NONE) { + if (Math.abs(dy) > MAX_Y) { + mTouchState = TOUCH_STATE_Y; + } else if (dx > MAX_X) { + mTouchState = TOUCH_STATE_X; + if (mOnSwipeListener != null) { + mOnSwipeListener.onSwipeStart(mTouchPosition); + } + } + } + return true; + } + } + return super.onInterceptTouchEvent(ev); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (ev.getAction() != MotionEvent.ACTION_DOWN && mTouchView == null) + return super.onTouchEvent(ev); + int action = ev.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + int oldPos = mTouchPosition; + mDownX = ev.getX(); + mDownY = ev.getY(); + mTouchState = TOUCH_STATE_NONE; + + mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY()); + + if (mTouchPosition == oldPos && mTouchView != null + && mTouchView.isOpen()) { + mTouchState = TOUCH_STATE_X; + mTouchView.onSwipe(ev); + return true; + } + + View view = getChildAt(mTouchPosition - getFirstVisiblePosition()); + + if (mTouchView != null && mTouchView.isOpen()) { + mTouchView.smoothCloseMenu(); + mTouchView = null; + // return super.onTouchEvent(ev); + // try to cancel the touch event + MotionEvent cancelEvent = MotionEvent.obtain(ev); + cancelEvent.setAction(MotionEvent.ACTION_CANCEL); + onTouchEvent(cancelEvent); + if (mOnMenuStateChangeListener != null) { + mOnMenuStateChangeListener.onMenuClose(oldPos); + } + return true; + } + if (view instanceof SwipeMenuLayout) { + mTouchView = (SwipeMenuLayout) view; + mTouchView.setSwipeDirection(mDirection); + } + if (mTouchView != null) { + mTouchView.onSwipe(ev); + } + break; + case MotionEvent.ACTION_MOVE: + //有些可能有header,要减去header再判断 + mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY()) - getHeaderViewsCount(); + //如果滑动了一下没完全展现,就收回去,这时候mTouchView已经赋值,再滑动另外一个不可以swip的view + //会导致mTouchView swip 。 所以要用位置判断是否滑动的是一个view + if (!mTouchView.getSwipEnable() || mTouchPosition != mTouchView.getPosition()) { + break; + } + float dy = Math.abs((ev.getY() - mDownY)); + float dx = Math.abs((ev.getX() - mDownX)); + if (mTouchState == TOUCH_STATE_X) { + if (mTouchView != null) { + mTouchView.onSwipe(ev); + } + getSelector().setState(new int[]{0}); + ev.setAction(MotionEvent.ACTION_CANCEL); + super.onTouchEvent(ev); + return true; + } else if (mTouchState == TOUCH_STATE_NONE) { + if (Math.abs(dy) > MAX_Y) { + mTouchState = TOUCH_STATE_Y; + } else if (dx > MAX_X) { + mTouchState = TOUCH_STATE_X; + if (mOnSwipeListener != null) { + mOnSwipeListener.onSwipeStart(mTouchPosition); + } + } + } + break; + // add by liutong start + // 当 listview 处于 有 父 view 的 时候 滑动 有时候 会 触发 cancel 事件 + case MotionEvent.ACTION_CANCEL: + if (mTouchState == TOUCH_STATE_X) { + if (mTouchView != null) { + boolean isBeforeOpen = mTouchView.isOpen(); + mTouchView.onSwipe(ev); + boolean isAfterOpen = mTouchView.isOpen(); + if (isBeforeOpen != isAfterOpen && mOnMenuStateChangeListener != null) { + if (isAfterOpen) { + mOnMenuStateChangeListener.onMenuOpen(mTouchPosition); + } else { + mOnMenuStateChangeListener.onMenuClose(mTouchPosition); + } + } + if (!isAfterOpen) { + mTouchPosition = -1; + mTouchView = null; + } + } + if (mOnSwipeListener != null) { + mOnSwipeListener.onSwipeEnd(mTouchPosition); + } + ev.setAction(MotionEvent.ACTION_CANCEL); + super.onTouchEvent(ev); + return true; + } + break; + // add by liutong start + case MotionEvent.ACTION_UP: + if (mTouchState == TOUCH_STATE_X) { + if (mTouchView != null) { + boolean isBeforeOpen = mTouchView.isOpen(); + mTouchView.onSwipe(ev); + boolean isAfterOpen = mTouchView.isOpen(); + if (isBeforeOpen != isAfterOpen && mOnMenuStateChangeListener != null) { + if (isAfterOpen) { + mOnMenuStateChangeListener.onMenuOpen(mTouchPosition); + } else { + mOnMenuStateChangeListener.onMenuClose(mTouchPosition); + } + } + if (!isAfterOpen) { + mTouchPosition = -1; + mTouchView = null; + } + } + if (mOnSwipeListener != null) { + mOnSwipeListener.onSwipeEnd(mTouchPosition); + } + ev.setAction(MotionEvent.ACTION_CANCEL); + super.onTouchEvent(ev); + return true; + } + break; + } + return super.onTouchEvent(ev); + } + + public void smoothOpenMenu(int position) { + if (position >= getFirstVisiblePosition() + && position <= getLastVisiblePosition()) { + View view = getChildAt(position - getFirstVisiblePosition()); + if (view instanceof SwipeMenuLayout) { + mTouchPosition = position; + if (mTouchView != null && mTouchView.isOpen()) { + mTouchView.smoothCloseMenu(); + } + mTouchView = (SwipeMenuLayout) view; + mTouchView.setSwipeDirection(mDirection); + mTouchView.smoothOpenMenu(); + } + } + } + + public void smoothCloseMenu(){ + if (mTouchView != null && mTouchView.isOpen()) { + mTouchView.smoothCloseMenu(); + } + } + + private int dp2px(int dp) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, + getContext().getResources().getDisplayMetrics()); + } + + public void setMenuCreator(SwipeMenuCreator menuCreator) { + this.mMenuCreator = menuCreator; + } + + public void setOnMenuItemClickListener( + OnMenuItemClickListener onMenuItemClickListener) { + this.mOnMenuItemClickListener = onMenuItemClickListener; + } + + public void setOnSwipeListener(OnSwipeListener onSwipeListener) { + this.mOnSwipeListener = onSwipeListener; + } + + public void setOnMenuStateChangeListener(OnMenuStateChangeListener onMenuStateChangeListener) { + mOnMenuStateChangeListener = onMenuStateChangeListener; + } + + public static interface OnMenuItemClickListener { + boolean onMenuItemClick(int position, SwipeMenu menu, int index); + } + + public static interface OnSwipeListener { + void onSwipeStart(int position); + + void onSwipeEnd(int position); + } + + public static interface OnMenuStateChangeListener { + void onMenuOpen(int position); + + void onMenuClose(int position); + } + + public void setSwipeDirection(int direction) { + mDirection = direction; + } + + /** + * 判断点击事件是否在某个view内 + * + * @param view + * @param ev + * @return + */ + public static boolean inRangeOfView(View view, MotionEvent ev) { + int[] location = new int[2]; + view.getLocationOnScreen(location); + int x = location[0]; + int y = location[1]; + if (ev.getRawX() < x || ev.getRawX() > (x + view.getWidth()) || ev.getRawY() < y || ev.getRawY() > (y + view.getHeight())) { + return false; + } + return true; + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int mExpandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); + super.onMeasure(widthMeasureSpec, mExpandSpec); + } +} diff --git a/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuView.java b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuView.java new file mode 100644 index 0000000..7027bca --- /dev/null +++ b/swipelistviewlibrary/src/main/java/com/yjn/swipelistview/swipelistviewlibrary/widget/SwipeMenuView.java @@ -0,0 +1,106 @@ +package com.yjn.swipelistview.swipelistviewlibrary.widget; + +import android.text.TextUtils; +import android.view.Gravity; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import java.util.List; + +/** + * + * @author baoyz + * @date 2014-8-23 + * + */ +public class SwipeMenuView extends LinearLayout implements OnClickListener { + + private SwipeMenuListView mListView; + private SwipeMenuLayout mLayout; + private SwipeMenu mMenu; + private OnSwipeItemClickListener onItemClickListener; + private int position; + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + } + + public SwipeMenuView(SwipeMenu menu, SwipeMenuListView listView) { + super(menu.getContext()); + if(listView != null){ + mListView = listView; + } + mMenu = menu; + List items = menu.getMenuItems(); + int id = 0; + for (SwipeMenuItem item : items) { + addItem(item, id++); + } + } + + private void addItem(SwipeMenuItem item, int id) { + LayoutParams params = new LayoutParams(item.getWidth(), + LayoutParams.MATCH_PARENT); + LinearLayout parent = new LinearLayout(getContext()); + parent.setId(id); + parent.setGravity(Gravity.CENTER); + parent.setOrientation(LinearLayout.VERTICAL); + parent.setLayoutParams(params); + parent.setBackgroundDrawable(item.getBackground()); + parent.setOnClickListener(this); + addView(parent); + + if (item.getIcon() != null) { + parent.addView(createIcon(item)); + } + if (!TextUtils.isEmpty(item.getTitle())) { + parent.addView(createTitle(item)); + } + + } + + private ImageView createIcon(SwipeMenuItem item) { + ImageView iv = new ImageView(getContext()); + iv.setImageDrawable(item.getIcon()); + return iv; + } + + private TextView createTitle(SwipeMenuItem item) { + TextView tv = new TextView(getContext()); + tv.setText(item.getTitle()); + tv.setGravity(Gravity.CENTER); + tv.setTextSize(item.getTitleSize()); + tv.setTextColor(item.getTitleColor()); + return tv; + } + + @Override + public void onClick(View v) { + if (onItemClickListener != null && mLayout.isOpen()) { + onItemClickListener.onItemClick(this, mMenu, v.getId()); + } + } + + public OnSwipeItemClickListener getOnSwipeItemClickListener() { + return onItemClickListener; + } + + public void setOnSwipeItemClickListener(OnSwipeItemClickListener onItemClickListener) { + this.onItemClickListener = onItemClickListener; + } + + public void setLayout(SwipeMenuLayout mLayout) { + this.mLayout = mLayout; + } + + public static interface OnSwipeItemClickListener { + void onItemClick(SwipeMenuView view, SwipeMenu menu, int index); + } +} diff --git a/swipelistviewlibrary/src/main/res/values/strings.xml b/swipelistviewlibrary/src/main/res/values/strings.xml new file mode 100644 index 0000000..0324dd8 --- /dev/null +++ b/swipelistviewlibrary/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + SwipeListViewLibrary + diff --git a/swipelistviewlibrary/src/test/java/com/yjn/swipelistview/swipelistviewlibrary/ExampleUnitTest.java b/swipelistviewlibrary/src/test/java/com/yjn/swipelistview/swipelistviewlibrary/ExampleUnitTest.java new file mode 100644 index 0000000..914cf52 --- /dev/null +++ b/swipelistviewlibrary/src/test/java/com/yjn/swipelistview/swipelistviewlibrary/ExampleUnitTest.java @@ -0,0 +1,15 @@ +package com.yjn.swipelistview.swipelistviewlibrary; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * To work on unit tests, switch the Test Artifact in the Build Variants view. + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file