diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 26c9ed5..1b83b44 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -103,10 +103,13 @@ android:name=".main.my.activity.PersonalProfileActivity" android:screenOrientation="portrait" /> + android:screenOrientation="portrait" /> + + - + StyleActivity { + Context mcontext; + OnViewClickListener onViewClickListener; + + public StyleAdapter(Context context, List list) { + super(R.layout.style_item, list); + this.mcontext = context; + } + + @Override + protected void convert(final BaseViewHolder helper, final StyleBean.ResultBean.DataBean item) { + WidgetTools.setTextfive((TextView) helper.getView(R.id.tv_style), "", item.getStyle()); + RelativeLayout rl_style = (RelativeLayout)helper.getView(R.id.rl_style); + rl_style.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + onViewClickListener.enterCusDetail(item); + } + }); + + } + + public void operationListenner(OnViewClickListener onViewClickListener){ + this.onViewClickListener = onViewClickListener; + } + + public interface OnViewClickListener{ + + void enterCusDetail(StyleBean.ResultBean.DataBean item); + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/fenghoo/seven/main/find/entity/StyleBean.java b/app/src/main/java/com/fenghoo/seven/main/find/entity/StyleBean.java new file mode 100644 index 0000000..2e4c9c2 --- /dev/null +++ b/app/src/main/java/com/fenghoo/seven/main/find/entity/StyleBean.java @@ -0,0 +1,99 @@ +package com.fenghoo.seven.main.find.entity; + +import com.fenghoo.seven.test.BaseModel; + +import java.util.List; + +/** + * Time: 2020/8/28 + * Author: jianbo + * Description: + */ +public class StyleBean extends BaseModel { + + /** + * result : {"msg":"成功","data":[{"style":"北欧","style_id":"1"}],"success":0} + * status : 0 + */ + + private ResultBean result; + private int status; + + public ResultBean getResult() { + return result; + } + + public void setResult(ResultBean result) { + this.result = result; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public static class ResultBean { + /** + * msg : 成功 + * data : [{"style":"北欧","style_id":"1"}] + * success : 0 + */ + + private String msg; + private int success; + private List data; + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public int getSuccess() { + return success; + } + + public void setSuccess(int success) { + this.success = success; + } + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } + + public static class DataBean { + /** + * style : 北欧 + * style_id : 1 + */ + + private String style; + private String style_id; + + public String getStyle() { + return style; + } + + public void setStyle(String style) { + this.style = style; + } + + public String getStyle_id() { + return style_id; + } + + public void setStyle_id(String style_id) { + this.style_id = style_id; + } + } + } +} diff --git a/app/src/main/java/com/fenghoo/seven/main/kehu/Bean/FirstEvent.java b/app/src/main/java/com/fenghoo/seven/main/kehu/Bean/FirstEvent.java new file mode 100644 index 0000000..7f4e28d --- /dev/null +++ b/app/src/main/java/com/fenghoo/seven/main/kehu/Bean/FirstEvent.java @@ -0,0 +1,21 @@ +package com.fenghoo.seven.main.kehu.Bean; + +/** + * Time: 2020/8/28 + * Author: jianbo + * Description: + */ +public class FirstEvent { + private String mMsg; + private String sTyle; + + public FirstEvent(String msg,String style) { + // TODO Auto-generated constructor stub + mMsg = msg; + sTyle = style; + } + public String getMsg(){ + return mMsg; + } + public String getStyle() { return sTyle; } +} diff --git a/app/src/main/java/com/fenghoo/seven/main/kehu/Bean/SecondEvent.java b/app/src/main/java/com/fenghoo/seven/main/kehu/Bean/SecondEvent.java new file mode 100644 index 0000000..40614bb --- /dev/null +++ b/app/src/main/java/com/fenghoo/seven/main/kehu/Bean/SecondEvent.java @@ -0,0 +1,17 @@ +package com.fenghoo.seven.main.kehu.Bean; + +/** + * Time: 2020/8/28 + * Author: jianbo + * Description: + */ +public class SecondEvent { + private String mMsg; + public SecondEvent(String msg) { + // TODO Auto-generated constructor stub + mMsg = msg; + } + public String getMsg(){ + return mMsg; + } +} diff --git a/app/src/main/java/com/fenghoo/seven/main/kehu/Bean/addCustomerBean.java b/app/src/main/java/com/fenghoo/seven/main/kehu/Bean/addCustomerBean.java new file mode 100644 index 0000000..cd259ce --- /dev/null +++ b/app/src/main/java/com/fenghoo/seven/main/kehu/Bean/addCustomerBean.java @@ -0,0 +1,123 @@ +package com.fenghoo.seven.main.kehu.Bean; + +/** + * Time: 2020/8/28 + * Author: jianbo + * Description: + */ +public class addCustomerBean { +// private String uid string 登录员工的uid 是 否 +// private String headimg string 头像 否 否 base64 空 +// private String name string 姓名 是 否 +// private String phone string 电话 是 否 +// private String wechat string 微信 否 否 空 +// private String address string 住址 否 否 空 +// private String decoration string 家装阶段 否 否 1:毛坯,2:精装,3:旧房改造 1 +// private String style_id string 风格id 否 否 空 +// private String budget string 预算 否 否 空 +// private String source string 客户来源 否 否 1:添加客户 1 +// private String customer_id string 客户id 否 否 有值代表完善信息,空代表添加 + + + private String uid=""; + private String headimg=""; + private String name=""; + + public String getUid() { + return uid; + } + + public void setUid(String uid) { + this.uid = uid; + } + + public String getHeadimg() { + return headimg; + } + + public void setHeadimg(String headimg) { + this.headimg = headimg; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getWechat() { + return wechat; + } + + public void setWechat(String wechat) { + this.wechat = wechat; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getDecoration() { + return decoration; + } + + public void setDecoration(String decoration) { + this.decoration = decoration; + } + + public String getStyle_id() { + return style_id; + } + + public void setStyle_id(String style_id) { + this.style_id = style_id; + } + + public String getBudget() { + return budget; + } + + public void setBudget(String budget) { + this.budget = budget; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + public String getCustomer_id() { + return customer_id; + } + + public void setCustomer_id(String customer_id) { + this.customer_id = customer_id; + } + + private String phone=""; + private String wechat=""; + private String address=""; + private String decoration="1"; + private String style_id=""; + private String budget=""; + private String source="1"; + private String customer_id=""; + +} diff --git a/app/src/main/java/com/fenghoo/seven/main/kehu/CustomerFragment.java b/app/src/main/java/com/fenghoo/seven/main/kehu/CustomerFragment.java index e3838c9..d922cc1 100644 --- a/app/src/main/java/com/fenghoo/seven/main/kehu/CustomerFragment.java +++ b/app/src/main/java/com/fenghoo/seven/main/kehu/CustomerFragment.java @@ -67,7 +67,10 @@ public class CustomerFragment extends MobanFragment { //信息完善 @Override public void uploadAvatar() { - + //进入添加客户和完善信息 + String customer_id = item.getCustomer_id(); + String source = item.getSource(); + ShowAty.AddCustomerActivity(getActivity(),customer_id,source); } }).show(); diff --git a/app/src/main/java/com/fenghoo/seven/main/kehu/Dialog/CusOperationDialog.java b/app/src/main/java/com/fenghoo/seven/main/kehu/Dialog/CusOperationDialog.java index 147b8b6..41604ae 100644 --- a/app/src/main/java/com/fenghoo/seven/main/kehu/Dialog/CusOperationDialog.java +++ b/app/src/main/java/com/fenghoo/seven/main/kehu/Dialog/CusOperationDialog.java @@ -73,15 +73,15 @@ public class CusOperationDialog extends Dialog implements View.OnClickListener { } dismiss(); break; - case R.id.rl_tv_kaidan://开单 + case R.id.rl_tv_uploadAvatar://信息完善 if (listener != null) { - listener.kaidanonClick(); + listener.uploadAvatar(); } dismiss(); break; - case R.id.rl_tv_uploadAvatar://上传头像 + case R.id.rl_tv_kaidan://删除客户 if (listener != null) { - listener.uploadAvatar(); + listener.kaidanonClick(); } dismiss(); break; diff --git a/app/src/main/java/com/fenghoo/seven/main/kehu/Dialog/RreplyDialog.java b/app/src/main/java/com/fenghoo/seven/main/kehu/Dialog/RreplyDialog.java index 6e67a2a..206c6dc 100644 --- a/app/src/main/java/com/fenghoo/seven/main/kehu/Dialog/RreplyDialog.java +++ b/app/src/main/java/com/fenghoo/seven/main/kehu/Dialog/RreplyDialog.java @@ -106,6 +106,7 @@ public class RreplyDialog extends Dialog implements View.OnClickListener { listener.uploadAvatar(); } dismiss(); + break; case R.id.reply_ima://快捷回复 if(flag){ reply_rcey.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/com/fenghoo/seven/main/kehu/MoActivity.java b/app/src/main/java/com/fenghoo/seven/main/kehu/MoActivity.java index 18b6d64..ab1c80e 100644 --- a/app/src/main/java/com/fenghoo/seven/main/kehu/MoActivity.java +++ b/app/src/main/java/com/fenghoo/seven/main/kehu/MoActivity.java @@ -58,9 +58,6 @@ public abstract class MoActivity extends BaseActivity { public View errorView; public TextView mLayTopTitle; - - - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -75,7 +72,7 @@ public abstract class MoActivity extends BaseActivity { private void initView(View mContentView) { mMarkingFragmentRecyclerView = (RecyclerView) findViewById(R.id.marking_fragment_recyclerView); - mSwl = mContentView.findViewById(R.id.srl); + mSwl = findViewById(R.id.srl); notDataView = this.getLayoutInflater().inflate(R.layout.empty_view, (ViewGroup) mMarkingFragmentRecyclerView.getParent(), false); notDataView.setOnClickListener(new View.OnClickListener() { @Override @@ -114,7 +111,7 @@ public abstract class MoActivity extends BaseActivity { private void refresh() { mNextRequestPage = 1; - markingtwoAdapter.setEnableLoadMore(false);//这里的作用是防止下拉刷新的时候还可以上拉加载 + // markingtwoAdapter.setEnableLoadMore(false);//这里的作用是防止下拉刷新的时候还可以上拉加载 requestData(); } diff --git a/app/src/main/java/com/fenghoo/seven/main/kehu/activity/AddCustomerActivity.java b/app/src/main/java/com/fenghoo/seven/main/kehu/activity/AddCustomerActivity.java index a56eeb8..3a272b4 100644 --- a/app/src/main/java/com/fenghoo/seven/main/kehu/activity/AddCustomerActivity.java +++ b/app/src/main/java/com/fenghoo/seven/main/kehu/activity/AddCustomerActivity.java @@ -2,30 +2,42 @@ package com.fenghoo.seven.main.kehu.activity; import android.content.Intent; import android.os.Bundle; +import android.view.View; import com.fenghoo.seven.R; +import com.fenghoo.seven.base.BaseActivity; import com.fenghoo.seven.main.kehu.ui.AddCusFragment; -import com.fenghoo.seven.utils.StatusBarUtil; - -import androidx.appcompat.app.AppCompatActivity; +import com.fenghoo.seven.widget.TitleBar; /** *添加客户和完善信息 */ -public class AddCustomerActivity extends AppCompatActivity{ - private static final int RC_CAMERA_AND_LOCATION = 100; +public class AddCustomerActivity extends BaseActivity { private static int REQUEST_CODE_CHOOSE = 100; private AddCusFragment addCusFragment; + private TitleBar mTitleBar; + private String customer_id=""; + private String source=""; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_add_customer); - StatusBarUtil.transparencyBar(this); //设置状态栏全透明 - StatusBarUtil.setStatusBarColor(this,R.color.colortheme); - addCusFragment = new AddCusFragment(); + mTitleBar = (TitleBar) findViewById(R.id.title_bar); + mTitleBar.setTitle("信息完善"); + initNormalBack(); + customer_id = getIntent().getStringExtra("customer_id"); + source = getIntent().getStringExtra("source"); + addCusFragment = new AddCusFragment(customer_id,source); getSupportFragmentManager().beginTransaction().replace(R.id.containerrr,addCusFragment).commit(); + findViewById(R.id.btn_comit).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + addCusFragment.comit(); + } + }); } @Override diff --git a/app/src/main/java/com/fenghoo/seven/main/kehu/activity/BudgetActivity.java b/app/src/main/java/com/fenghoo/seven/main/kehu/activity/BudgetActivity.java new file mode 100644 index 0000000..e286aee --- /dev/null +++ b/app/src/main/java/com/fenghoo/seven/main/kehu/activity/BudgetActivity.java @@ -0,0 +1,68 @@ +package com.fenghoo.seven.main.kehu.activity; + +import android.os.Bundle; +import android.view.View; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.fenghoo.seven.R; +import com.fenghoo.seven.main.kehu.Bean.FirstEvent; +import com.fenghoo.seven.main.kehu.Bean.SecondEvent; +import com.fenghoo.seven.main.kehu.MoActivity; +import com.fenghoo.seven.utils.WidgetTools; +import com.fenghoo.seven.widget.TitleBar; + +import java.util.ArrayList; + +import androidx.recyclerview.widget.LinearLayoutManager; +import de.greenrobot.event.EventBus; + +/** + * + */ +public class BudgetActivity extends MoActivity { + + private ArrayList budgets = new ArrayList<>(); + private TitleBar mTitleBar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mTitleBar = (TitleBar) findViewById(R.id.title_bar); + mTitleBar.setTitle("选择预算"); + initNormalBack(); + } + + @Override + public void initAdapter() { + mMarkingFragmentRecyclerView.setLayoutManager(new LinearLayoutManager(BudgetActivity.this)); + mMarkingFragmentRecyclerView.setAdapter(new BaseQuickAdapter(R.layout.style_item, budgets) { + @Override + protected void convert(final BaseViewHolder helper, final String item) { + WidgetTools.setTextfive((TextView) helper.getView(R.id.tv_style), "", item); + RelativeLayout rl_style = (RelativeLayout)helper.getView(R.id.rl_style); + rl_style.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + EventBus.getDefault().post(new SecondEvent(item)); + finish(); + } + }); + } + }); + } + + @Override + public void requestData() { + mSwl.setRefreshing(false); + budgets.add("0万-5万"); + budgets.add("5万-10万"); + budgets.add("10万-15万"); + budgets.add("15万-20万"); + budgets.add("20万以上"); + + } + +} diff --git a/app/src/main/java/com/fenghoo/seven/main/kehu/activity/ShowAty.java b/app/src/main/java/com/fenghoo/seven/main/kehu/activity/ShowAty.java index e7d8534..45f3582 100644 --- a/app/src/main/java/com/fenghoo/seven/main/kehu/activity/ShowAty.java +++ b/app/src/main/java/com/fenghoo/seven/main/kehu/activity/ShowAty.java @@ -120,10 +120,22 @@ public class ShowAty { * @param * @return */ - public static void AddCustomerActivity(Context ctx) { + public static void AddCustomerActivity(Context ctx,String customer_id,String source) { Intent i = new Intent(ctx, AddCustomerActivity.class); + i.putExtra("customer_id",customer_id); + i.putExtra("source",source); ctx.startActivity(i); } + public static void StyleActivity(Context ctx) { + Intent i = new Intent(ctx, StyleActivity.class); + ctx.startActivity(i); + } + + public static void BudgetActivity(Context ctx) { + Intent i = new Intent(ctx, BudgetActivity.class); + ctx.startActivity(i); + } + } diff --git a/app/src/main/java/com/fenghoo/seven/main/kehu/activity/StyleActivity.java b/app/src/main/java/com/fenghoo/seven/main/kehu/activity/StyleActivity.java new file mode 100644 index 0000000..9dc4db4 --- /dev/null +++ b/app/src/main/java/com/fenghoo/seven/main/kehu/activity/StyleActivity.java @@ -0,0 +1,92 @@ +package com.fenghoo.seven.main.kehu.activity; + +import android.os.Bundle; + +import com.fenghoo.seven.JsonUtils; +import com.fenghoo.seven.R; +import com.fenghoo.seven.main.find.adapter.StyleAdapter; +import com.fenghoo.seven.main.find.entity.StyleBean; +import com.fenghoo.seven.main.kehu.Bean.FirstEvent; +import com.fenghoo.seven.main.kehu.Bean.WxuSerinfo; +import com.fenghoo.seven.main.kehu.MoActivity; +import com.fenghoo.seven.okgonet.NetApi; +import com.fenghoo.seven.okgonet.Observer; +import com.fenghoo.seven.widget.TitleBar; +import com.lzy.okgo.model.Response; + +import java.util.List; + +import androidx.recyclerview.widget.LinearLayoutManager; +import de.greenrobot.event.EventBus; + +/** + * + */ +public class StyleActivity extends MoActivity { + + private TitleBar mTitleBar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mTitleBar = (TitleBar) findViewById(R.id.title_bar); + mTitleBar.setTitle("选择风格"); + initNormalBack(); + } + + @Override + public void initAdapter() { + mMarkingFragmentRecyclerView.setLayoutManager(new LinearLayoutManager(StyleActivity.this)); + StyleAdapter markingtwoAdapter = new StyleAdapter(StyleActivity.this, null); + getAdpter(markingtwoAdapter); + mMarkingFragmentRecyclerView.setAdapter(markingtwoAdapter); + markingtwoAdapter.operationListenner(new StyleAdapter.OnViewClickListener() { + @Override + public void enterCusDetail(StyleBean.ResultBean.DataBean item) { + String style_id = item.getStyle_id(); + String style = item.getStyle(); + EventBus.getDefault().post(new FirstEvent(style_id,style)); + finish(); + } + }); + } + + @Override + public void requestData() { + new NetApi().style().subscribe(new Observer() { + @Override + public void onNext(Response response) { + String body = (String) response.body(); + StyleBean.ResultBean result = JsonUtils.fromJson(body, StyleBean.class).getResult(); + mSwl.setRefreshing(false); + if (result != null && String.valueOf(result.getSuccess()).equals("0")) { + + List data = result.getData(); + if (data.size() == 0) { + markingtwoAdapter.setEmptyView(notDataView); + return; + } + if (mNextRequestPage == 1) { + setData(true, data); + } else { + setData(false, data); + } + } else { + setData(true, null); + markingtwoAdapter.setEmptyView(notDataView); + mSwl.setRefreshing(false); + } + } + @Override + public void onError(Exception e) { + e.printStackTrace(); + markingtwoAdapter.setEmptyView(errorView); + mSwl.setRefreshing(false); + } + }); + } + @Override + public void onDestroy() { + super.onDestroy(); + } +} diff --git a/app/src/main/java/com/fenghoo/seven/main/kehu/ui/AddCusFragment.java b/app/src/main/java/com/fenghoo/seven/main/kehu/ui/AddCusFragment.java index 23ce477..359d895 100644 --- a/app/src/main/java/com/fenghoo/seven/main/kehu/ui/AddCusFragment.java +++ b/app/src/main/java/com/fenghoo/seven/main/kehu/ui/AddCusFragment.java @@ -4,54 +4,111 @@ import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; +import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.ViewGroup; +import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.BaseViewHolder; +import com.fenghoo.seven.JsonUtils; import com.fenghoo.seven.R; -import com.fenghoo.seven.main.Fragment.MoFragment; +import com.fenghoo.seven.base.BaseBean; +import com.fenghoo.seven.main.kehu.Bean.FirstEvent; import com.fenghoo.seven.main.kehu.Bean.LabelBean; +import com.fenghoo.seven.main.kehu.Bean.SecondEvent; +import com.fenghoo.seven.main.kehu.Bean.addCustomerBean; +import com.fenghoo.seven.main.kehu.MobanFragment; +import com.fenghoo.seven.main.kehu.activity.ShowAty; import com.fenghoo.seven.main.kehu.adapter.AddCusAdapter; +import com.fenghoo.seven.okgonet.NetApi; +import com.fenghoo.seven.okgonet.Observer; +import com.fenghoo.seven.utils.AbImageUtil; +import com.fenghoo.seven.utils.AbStrUtil; import com.fenghoo.seven.utils.GlideTools; +import com.fenghoo.seven.utils.ImageUtils; import com.fenghoo.seven.utils.ToastUtils; +import com.fenghoo.seven.utils.checkVersionsUtils.ProfileSpUtils; +import com.fenghoo.seven.widget.CircleImageView; +import com.lzy.okgo.model.Response; import com.tbruyelle.rxpermissions2.RxPermissions; import com.zhihu.matisse.Matisse; import com.zhihu.matisse.MimeType; import com.zhihu.matisse.engine.impl.PicassoEngine; import com.zhihu.matisse.internal.entity.CaptureStrategy; +import java.io.File; import java.util.ArrayList; import java.util.List; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import de.greenrobot.event.EventBus; import io.reactivex.disposables.Disposable; - -import static android.app.Activity.RESULT_OK; +import top.zibin.luban.CompressionPredicate; +import top.zibin.luban.Luban; +import top.zibin.luban.OnCompressListener; /** * 添加客户 */ -public class AddCusFragment extends AddCusParFragment { +public class AddCusFragment extends MobanFragment implements View.OnClickListener{ private RecyclerView recy_10; private String selectType="1"; - private ImageView imageView; + private CircleImageView imageView; private static int REQUEST_CODE_CHOOSE = 100; //调取系统摄像头的请求码 private static final int MY_ADD_CASE_CALL_PHONE = 6; List result; List resultPath; + private final addCustomerBean addCustomerBean; + private EditText textView0; + private EditText textView4; + private EditText textView6; + private EditText textView8; + private TextView textView12; + private TextView textView14; + private String customer_id; + private String source; + private ArrayList label=new ArrayList<>(); - public AddCusFragment() { + public AddCusFragment(String customer_id,String source) { super(); + this.customer_id=customer_id; + this.source=source; + addCustomerBean = new addCustomerBean(); + EventBus.getDefault().register(this); + } + /** + * @description 接收选择的风格id + * @param + * @return + */ + public void onEvent(FirstEvent event) { + if (null != event ) { + String style_id = event.getMsg(); + addCustomerBean.setStyle_id(style_id); + textView12.setText(event.getStyle()); + } + } + /** + * @description 接收选择的预算 + * @param + * @return + */ + public void onEventMainThread(SecondEvent event) { + if (null != event ) { + String budget = event.getMsg(); + addCustomerBean.setBudget(budget); + textView14.setText(budget); + } } @Override @@ -66,7 +123,7 @@ public class AddCusFragment extends AddCusParFragment { private View getHeaderView() { View view = getLayoutInflater().inflate(R.layout.addcus_head_view, (ViewGroup) mMarkingFragmentRecyclerView.getParent(), false); - imageView = (ImageView) view.findViewById(R.id.imageView); + imageView = (CircleImageView) view.findViewById(R.id.imageView); imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -74,11 +131,81 @@ public class AddCusFragment extends AddCusParFragment { } }); recy_10 = (RecyclerView) view.findViewById(R.id.recy_10); - ArrayList label = addData(); + label = addData(); setLabel(label); + + textView0 = (EditText) view.findViewById(R.id.textView0); + textView4 = (EditText) view.findViewById(R.id.textView4); + textView6 = (EditText) view.findViewById(R.id.textView6); + textView8 = (EditText) view.findViewById(R.id.textView8); + textView12 = (TextView) view.findViewById(R.id.textView12); + textView14 = (TextView) view.findViewById(R.id.textView14); + ConstraintLayout constraintLayout7 = (ConstraintLayout) view.findViewById(R.id.constraintLayout7); + constraintLayout7.setOnClickListener(this); + ConstraintLayout constraintLayout8 = (ConstraintLayout) view.findViewById(R.id.constraintLayout8); + constraintLayout8.setOnClickListener(this); return view; } + public void comit(){ + addCustomerBean.setName(textView0.getText().toString()); + addCustomerBean.setPhone(textView4.getText().toString()); + addCustomerBean.setWechat(textView6.getText().toString()); + addCustomerBean.setAddress(textView8.getText().toString()); + addCustomerBean.setSource(source); + addCustomerBean.setUid(ProfileSpUtils.getInstance().getUserProfie().getData().getUuid()); + addCustomerBean.setCustomer_id(customer_id); + for(int i=0;i() { + @Override + public void onNext(Response response) { + String body = (String) response.body(); + BaseBean.ResultBean result = JsonUtils.fromJson(body, BaseBean.class).getResult(); + if(result.getSuccess()==0){ + getActivity().finish(); + }else { + String msg = result.getMsg(); + ToastUtils.showToast(mContext, msg); + } + } + @Override + public void onError(Exception e) { + e.printStackTrace(); + } + }); + } + private ArrayList addData() { ArrayList label = new ArrayList<>(); LabelBean labelBean = new LabelBean(); @@ -222,11 +349,7 @@ public class AddCusFragment extends AddCusParFragment { @Override public void requestData() { - } - - @Override - public void onDestroy() { - super.onDestroy(); + mSwl.setRefreshing(false); } @@ -238,6 +361,35 @@ public class AddCusFragment extends AddCusParFragment { String s = uri.toString(); Log.e("url==",s); GlideTools.init(mContext).displaypic(imageView, resultPath.get(0), R.mipmap.icon_default_head); + File file = new File(resultPath.get(0)); + // 压缩文件 + Luban.with(getActivity()) + .load(file) + .ignoreBy(100) + .filter(new CompressionPredicate() { + @Override + public boolean apply(String path) { + return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif")); + } + }) + .setCompressListener(new OnCompressListener() { + @Override + public void onStart() { + Log.e("测试", "开始"); + } + + @Override + public void onSuccess(File file) { + //转换成功后的文件 + String resultt = AbImageUtil.bitmapToBase64(ImageUtils.getBitmap(file)); + addCustomerBean.setHeadimg(resultt); + } + + @Override + public void onError(Throwable e) { + Log.e("测试", "失败"); + } + }).launch(); // // 图片选择结果回调 // String paymentpaper = ""; // selectList = PictureSelector.obtainMultipleResult(data); @@ -258,11 +410,26 @@ public class AddCusFragment extends AddCusParFragment { // sBuffer.append(resultt); // paymentpaper = sBuffer.toString(); // } -// //引入黑名单的帮助类 -// heimingdanHelper = HeimingdanHelper.of(getActivity(), paymentpaper, cameraInfo, "", uid); -// heimingdanHelper.huoqutuianlujing(); -// heimingdanHelper.setzhilujing(path); // //上传头像 // upLoadAvatar(paymentpaper); } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.constraintLayout7: + ShowAty.StyleActivity(getActivity()); + break; + case R.id.constraintLayout8: + ShowAty.BudgetActivity(getActivity()); + break; + + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + } } diff --git a/app/src/main/java/com/fenghoo/seven/main/kehu/ui/AddCusParFragment.java b/app/src/main/java/com/fenghoo/seven/main/kehu/ui/AddCusParFragment.java deleted file mode 100644 index d68e261..0000000 --- a/app/src/main/java/com/fenghoo/seven/main/kehu/ui/AddCusParFragment.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.fenghoo.seven.main.kehu.ui; - -import android.annotation.SuppressLint; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import com.chad.library.adapter.base.BaseQuickAdapter; -import com.fenghoo.seven.R; -import com.fenghoo.seven.base.BaseFragment; -import com.fenghoo.seven.main.entity.Savaselect; - -import java.util.List; - -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; - - -@SuppressLint("ValidFragment") -public abstract class AddCusParFragment extends BaseFragment { - public static final String ARG_PAGE = "ARG_PAGE"; - private boolean IS_LOADED = false; - private static int mSerial = 0; - private boolean isFirst = true; - @SuppressLint("HandlerLeak") - private Handler handler = new Handler() { - public void handleMessage(Message msg) { - Log.e("tag", "IS_LOADED=" + IS_LOADED); - if (!IS_LOADED) { - IS_LOADED = true; - //请求我的客户已流失数据 - requesdata(); - } - return; - } - - }; - public Savaselect savaselectbean; - private RelativeLayout rl_top; - private RelativeLayout layTop_left_tv; - - public AddCusParFragment() { - - } - public BaseQuickAdapter markingtwoAdapter; - public void sendMessage() { - Message message = handler.obtainMessage(); - message.sendToTarget(); - } - - private String uid; - public RecyclerView mMarkingFragmentRecyclerView; - public int mNextRequestPage = 1; - private static final int PAGE_SIZE = 10; - View view; - public View notDataView; - public View errorView; - public TextView mLayTopTitle; - //头部图片(轮播图的高度) - public int mRecyclerHeaderBannerHeight; - //头部的高度 - public int mRecyclerHeaderHeight; - private int mTextViewHeight; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mContext = getActivity(); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - if (view != null) { - ViewGroup parent = (ViewGroup) view.getParent(); - if (parent != null) { - parent.removeView(view); - } - return view; - } - view = inflater.inflate(R.layout.mobanfragment, container, false); - initView(view); - //设置页和当前页一致时加载,防止预加载 - if (isFirst) { - isFirst = false; - sendMessage(); - } - return view; - } - - private void initView(View mContentView) { - - rl_top = (RelativeLayout) view.findViewById(R.id.rl_top); - mLayTopTitle = (TextView) view.findViewById(R.id.layTop_title); - layTop_left_tv = (RelativeLayout) view.findViewById(R.id.layTop_left_tv); - layTop_left_tv.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - getActivity().finish(); - } - }); - mLayTopTitle.setText("信息完善"); - Thickening(mLayTopTitle); - mMarkingFragmentRecyclerView = (RecyclerView) view.findViewById(R.id.marking_fragment_recyclerView); - notDataView = getActivity().getLayoutInflater().inflate(R.layout.empty_view, (ViewGroup) mMarkingFragmentRecyclerView.getParent(), false); - notDataView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // refresh(); - } - }); - errorView = getActivity().getLayoutInflater().inflate(R.layout.error_view, (ViewGroup) mMarkingFragmentRecyclerView.getParent(), false); - errorView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // onRefresh(); - } - }); - - } - - - public void requesdata() { - initAdapter(); -// initRefreshLayout(); -// mSwl.setRefreshing(true); -// refresh(); - } - - public abstract void initAdapter(); - - - public void setData(boolean isRefresh, List data) { - mNextRequestPage++; - final int size = data == null ? 0 : data.size(); - if (isRefresh) { - markingtwoAdapter.setNewData(data); - } else { - if (size > 0) { - markingtwoAdapter.addData(data); - } - } - if (size < PAGE_SIZE) { - //第一页如果不够一页就不显示没有更多数据布局 - markingtwoAdapter.loadMoreEnd(isRefresh); - } else { - markingtwoAdapter.loadMoreComplete(); - } - } - - - public abstract void requestData(); - - public void getAdpter(BaseQuickAdapter markingtwoAdapter){ - this.markingtwoAdapter=markingtwoAdapter; - } - - - @Override - public void onDestroy() { - super.onDestroy(); - - } - -} diff --git a/app/src/main/java/com/fenghoo/seven/okgonet/HttpConstants.java b/app/src/main/java/com/fenghoo/seven/okgonet/HttpConstants.java index 179f995..689c06a 100644 --- a/app/src/main/java/com/fenghoo/seven/okgonet/HttpConstants.java +++ b/app/src/main/java/com/fenghoo/seven/okgonet/HttpConstants.java @@ -432,6 +432,16 @@ public class HttpConstants { */ public static String URi_device_AppCustomer_fpOrderInfo = URiBase + "/device/AppCustomer/fpOrderInfo"; + /** + * 风格 + */ + public static String URi_device_AppCustomer_style = URiBase + "/device/AppCustomer/style"; + + /** + * 添加客户和完善信息 + */ + public static String URi_device_AppCustomer_addCustomer = URiBase + "/device/AppCustomer/addCustomer"; + } diff --git a/app/src/main/java/com/fenghoo/seven/okgonet/NetApi.java b/app/src/main/java/com/fenghoo/seven/okgonet/NetApi.java index 4a3f8e0..bd440a7 100644 --- a/app/src/main/java/com/fenghoo/seven/okgonet/NetApi.java +++ b/app/src/main/java/com/fenghoo/seven/okgonet/NetApi.java @@ -421,4 +421,101 @@ public class NetApi { } + + + + /** + * style + */ + public Observable style() { + + return new Observable() { + @Override + public void subscribe(final Observer observer) { + + OkGo.post(HttpConstants.URi_device_AppCustomer_style) + .converter(new StringConvert())// + .cacheMode(CacheMode.NO_CACHE) //无缓存模式 CacheMode.NO_CACHE + .adapt(new ObservableResponse())// + .subscribeOn(Schedulers.io())// + .observeOn(AndroidSchedulers.mainThread())// + .subscribe(new io.reactivex.Observer>() { + + @Override + public void onSubscribe(@NonNull Disposable d) { + // addDisposable(d); + } + + @Override + public void onNext(@NonNull Response response) { + observer.onNext(response); + } + + @Override + public void onError(@NonNull Throwable e) { + e.printStackTrace(); + + } + + @Override + public void onComplete() { + + } + }); + } + }; + + } + + public Observable addCustomer(final String uid, final String headimg, final String name, final String phone, final String wechat, final String address, final String decoration, final String style_id, final String budget, final String source, final String customer_id) { + + return new Observable() { + @Override + public void subscribe(final Observer observer) { + + OkGo.post(HttpConstants.URi_device_AppCustomer_addCustomer) + .params("uid", uid) + .params("headimg", headimg) + .params("name", name) + .params("phone", phone) + .params("wechat", wechat) + .params("address", address) + .params("decoration", decoration) + .params("style_id", style_id) + .params("budget", budget) + .params("source", source) + .params("customer_id", customer_id) + .converter(new StringConvert())// + .cacheMode(CacheMode.NO_CACHE) //无缓存模式 CacheMode.NO_CACHE + .adapt(new ObservableResponse())// + .subscribeOn(Schedulers.io())// + .observeOn(AndroidSchedulers.mainThread())// + .subscribe(new io.reactivex.Observer>() { + + @Override + public void onSubscribe(@NonNull Disposable d) { + // addDisposable(d); + } + + @Override + public void onNext(@NonNull Response response) { + observer.onNext(response); + } + + @Override + public void onError(@NonNull Throwable e) { + e.printStackTrace(); + + } + + @Override + public void onComplete() { + + } + }); + } + }; + + } + } \ No newline at end of file diff --git a/app/src/main/java/com/fenghoo/seven/utils/AbImageUtil.java b/app/src/main/java/com/fenghoo/seven/utils/AbImageUtil.java new file mode 100644 index 0000000..211f758 --- /dev/null +++ b/app/src/main/java/com/fenghoo/seven/utils/AbImageUtil.java @@ -0,0 +1,750 @@ +/* + * + */ +package com.fenghoo.seven.utils; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff.Mode; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.util.Base64; +import android.view.View; +import android.view.View.MeasureSpec; +import android.widget.ImageView; + + +import com.fenghoo.seven.R; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +// TODO: Auto-generated Javadoc + +/** + * 描述:图片处理类. + * + */ +public class AbImageUtil { + + /** + * The tag. + */ + private static String TAG = "AbImageUtil"; + + + + private static OnImageUtilsListener onImageUtilsListener; + + public void setOnImageUtilsListener(OnImageUtilsListener listener) { + onImageUtilsListener = listener; + } + + public interface OnImageUtilsListener { + void backBitmap(Bitmap bt); + } + + /** + * 描述:缩放图片.压缩 + * + * @param file File对象 + * @param newWidth 新图片的宽 + * @param newHeight 新图片的高 + * @return Bitmap 新图片 + */ + @SuppressWarnings("resource") + public static Bitmap scaleImg(File file, int newWidth, int newHeight) { + Bitmap resizeBmp = null; + try { + BitmapFactory.Options opts = new BitmapFactory.Options(); + // 设置为true,decodeFile先不创建内存 只获取一些解码边界信息即图片大小信息 + opts.inJustDecodeBounds = true; + // BitmapFactory.decodeFile(file.getPath(), opts); + BitmapFactory.decodeFileDescriptor(new FileInputStream(file.getPath()).getFD(), null, opts); + if (newWidth != -1 && newHeight != -1) { + // inSampleSize=2表示图片宽高都为原来的二分之一,即图片为原来的四分之一 + // 缩放可以将像素点打薄 + int srcWidth = opts.outWidth; // 获取图片的原始宽度 + int srcHeight = opts.outHeight;// 获取图片原始高度 + int destWidth = 0; + int destHeight = 0; + // 缩放的比例 + double ratio = 0.0; + if (srcWidth < newWidth || srcHeight < newHeight) { + ratio = 0.0; + destWidth = srcWidth; + destHeight = srcHeight; + // 按比例计算缩放后的图片大小 + } else if (srcWidth > srcHeight) { + ratio = (double) srcWidth / newWidth; + destWidth = newWidth; + destHeight = (int) (srcHeight / ratio); + } else { + ratio = (double) srcHeight / newHeight; + destHeight = newHeight; + destWidth = (int) (srcWidth / ratio); + } + // 缩放的比例,缩放是很难按准备的比例进行缩放的,目前我只发现只能通过inSampleSize来进行缩放,其值表明缩放的倍数,SDK中建议其值是2的指数值 + opts.inSampleSize = (int) ratio + 1; + // 设置大小 + opts.outHeight = destHeight; + opts.outWidth = destWidth; + } else { + opts.inSampleSize = 1; + } + // 创建内存 + opts.inJustDecodeBounds = false; + // 使图片不抖动 + opts.inDither = false; + resizeBmp = BitmapFactory.decodeFileDescriptor(new FileInputStream(file.getPath()).getFD(), null, opts); + // resizeBmp = BitmapFactory.decodeFile(file.getPath(), opts); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return resizeBmp; + } + + /** + * 描述:缩放图片,不压缩的缩放. + * + * @param bitmap the bitmap + * @param newWidth 新图片的宽 + * @param newHeight 新图片的高 + * @return Bitmap 新图片 + */ + public static Bitmap scaleImg(Bitmap bitmap, int newWidth, int newHeight) { + if (bitmap == null) { + return null; + } + if (newHeight <= 0 || newWidth <= 0) { + return bitmap; + } + // 获得图片的宽高 + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + + if (width <= 0 || height <= 0) { + return null; + } + // 计算缩放比例 + float scaleWidth = ((float) newWidth) / width; + float scaleHeight = ((float) newHeight) / height; + // 取得想要缩放的matrix参数 + Matrix matrix = new Matrix(); + matrix.postScale(scaleWidth, scaleHeight); + // 得到新的图片 + Bitmap newBm = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true); + return newBm; + } + + /** + * 描述:缩放图片. + * + * @param bitmap the bitmap + * @param scale 比例 + * @return Bitmap 新图片 + */ + public static Bitmap scaleImg(Bitmap bitmap, float scale) { + Bitmap resizeBmp = null; + try { + // 获取Bitmap资源的宽和高 + int bmpW = bitmap.getWidth(); + int bmpH = bitmap.getHeight(); + // 注意这个Matirx是android.graphics底下的那个 + Matrix mt = new Matrix(); + // 设置缩放系数,分别为原来的0.8和0.8 + mt.postScale(scale, scale); + resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bmpW, bmpH, mt, true); + } catch (Exception e) { + e.printStackTrace(); + } + return resizeBmp; + } + + /** + * 描述:裁剪图片. + * + * @param file File对象 + * @param newWidth 新图片的宽 + * @param newHeight 新图片的高 + * @return Bitmap 新图片 + */ + public static Bitmap cutImg(File file, int newWidth, int newHeight) { + Bitmap newBitmap = null; + try { + BitmapFactory.Options opts = new BitmapFactory.Options(); + // 设置为true,decodeFile先不创建内存 只获取一些解码边界信息即图片大小信息 + opts.inJustDecodeBounds = true; + BitmapFactory.decodeFileDescriptor(new FileInputStream(file.getPath()).getFD(), null, opts); + // BitmapFactory.decodeFile(file.getPath(), opts); + if (newWidth != -1 && newHeight != -1) { + // inSampleSize=2表示图片宽高都为原来的二分之一,即图片为原来的四分之一 + // 缩放可以将像素点打薄,裁剪前将图片缩放一些 + int srcWidth = opts.outWidth; // 获取图片的原始宽度 + int srcHeight = opts.outHeight;// 获取图片原始高度 + int destWidth = 0; + int destHeight = 0; + int cutSrcWidth = newWidth * 2; + int cutSrcHeight = newHeight * 2; + + // 缩放的比例 + double ratio = 0.0; + if (srcWidth < cutSrcWidth || srcHeight < cutSrcHeight) { + ratio = 0.0; + destWidth = srcWidth; + destHeight = srcHeight; + // 按比例计算缩放后的图片大小 + } else if (srcWidth > srcHeight) { + ratio = (double) srcWidth / cutSrcWidth; + destWidth = cutSrcWidth; + destHeight = (int) (srcHeight / ratio); + } else { + ratio = (double) srcHeight / cutSrcHeight; + destHeight = cutSrcHeight; + destWidth = (int) (srcWidth / ratio); + } + // 缩放的比例,缩放是很难按准备的比例进行缩放的,目前我只发现只能通过inSampleSize来进行缩放,其值表明缩放的倍数,SDK中建议其值是2的指数值 + opts.inSampleSize = (int) ratio + 1; + // 设置大小 + opts.outHeight = destHeight; + opts.outWidth = destWidth; + } else { + opts.inSampleSize = 1; + } + // 创建内存 + opts.inJustDecodeBounds = false; + // 使图片不抖动 + opts.inDither = false; + // Bitmap resizeBmp = BitmapFactory.decodeFile(file.getPath(), opts); + Bitmap resizeBmp = BitmapFactory.decodeFileDescriptor(new FileInputStream(file.getPath()).getFD(), null, opts); + if (resizeBmp != null) { + newBitmap = cutImg(resizeBmp, newWidth, newHeight); + } + if (newBitmap != null) { + return newBitmap; + } else { + return resizeBmp; + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + return newBitmap; + } catch (IOException e) { + e.printStackTrace(); + return newBitmap; + } + } + + /** + * 描述:裁剪图片. + * + * @param bitmap the bitmap + * @param newWidth 新图片的宽 + * @param newHeight 新图片的高 + * @return Bitmap 新图片 + */ + public static Bitmap cutImg(Bitmap bitmap, int newWidth, int newHeight) { + if (bitmap == null) { + return null; + } + Bitmap newBitmap = null; + if (newHeight <= 0 || newWidth <= 0) { + return bitmap; + } + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + + if (width <= 0 || height <= 0) { + return null; + } + int offsetX = 0; + int offsetY = 0; + + if (width > newWidth) { + offsetX = (width - newWidth) / 2; + } + if (height > newHeight) { + offsetY = (height - newHeight) / 2; + } + + newBitmap = Bitmap.createBitmap(bitmap, offsetX, offsetY, newWidth, newHeight); + return newBitmap; + } + + /** + * Drawable转Bitmap. + * + * @param drawable 要转化的Drawable + * @return Bitmap + */ + public static Bitmap drawableToBitmap(Drawable drawable) { + Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), drawable.getOpacity() != PixelFormat.OPAQUE ? Config.ARGB_8888 : Config.RGB_565); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); + drawable.draw(canvas); + return bitmap; + } + + /** + * Drawable对象转换Bitmap对象. + * + * @param bitmap 要转化的Bitmap对象 + * @return Drawable 转化完成的Drawable对象 + */ + @SuppressWarnings("deprecation") + public static Drawable bitmapToDrawable(Bitmap bitmap) { + BitmapDrawable mBitmapDrawable = null; + try { + if (bitmap == null) { + return null; + } + mBitmapDrawable = new BitmapDrawable(bitmap); + } catch (Exception e) { + e.printStackTrace(); + } + return mBitmapDrawable; + } + + /** + * 将Bitmap转换为byte[]. + * + * @param bitmap the bitmap + * @param mCompressFormat 图片格式 Bitmap.CompressFormat.JPEG,CompressFormat.PNG + * @param needRecycle 是否需要回收 + * @return byte[] 图片的byte[] + */ + public static byte[] bitmap2Bytes(Bitmap bitmap, Bitmap.CompressFormat mCompressFormat, final boolean needRecycle) { + byte[] result = null; + ByteArrayOutputStream output = null; + try { + output = new ByteArrayOutputStream(); + bitmap.compress(mCompressFormat, 100, output); + result = output.toByteArray(); + if (needRecycle) { + bitmap.recycle(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (output != null) { + try { + output.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + return result; + } + + /** + * 描述:将byte[]转换为Bitmap. + * + * @param b 图片格式的byte[]数组 + * @return bitmap 得到的Bitmap + */ + public static Bitmap bytes2Bimap(byte[] b) { + Bitmap bitmap = null; + try { + if (b.length != 0) { + bitmap = BitmapFactory.decodeByteArray(b, 0, b.length); + } + } catch (Exception e) { + e.printStackTrace(); + } + return bitmap; + } + + /** + * 将ImageView转换为Bitmap. + * + * @param view 要转换为bitmap的View + * @return byte[] 图片的byte[] + */ + public static Bitmap imageView2Bitmap(ImageView view) { + Bitmap bitmap = null; + try { + bitmap = Bitmap.createBitmap(view.getDrawingCache()); + view.setDrawingCacheEnabled(false); + } catch (Exception e) { + e.printStackTrace(); + } + return bitmap; + } + + /** + * 将View转换为Drawable.需要最上层布局为Linearlayout + * + * @param view 要转换为Drawable的View + * @return BitmapDrawable Drawable + */ + @SuppressWarnings("deprecation") + public static Drawable view2Drawable(View view) { + BitmapDrawable mBitmapDrawable = null; + try { + Bitmap newbmp = view2Bitmap(view); + if (newbmp != null) { + mBitmapDrawable = new BitmapDrawable(newbmp); + } + } catch (Exception e) { + e.printStackTrace(); + } + return mBitmapDrawable; + } + + /** + * 将View转换为Bitmap.需要最上层布局为Linearlayout + * + * @param view 要转换为bitmap的View + * @return byte[] 图片的byte[] + */ + public static Bitmap view2Bitmap(View view) { + Bitmap bitmap = null; + try { + if (view != null) { + view.setDrawingCacheEnabled(true); + view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); + view.buildDrawingCache(); + bitmap = view.getDrawingCache(); + } + } catch (Exception e) { + e.printStackTrace(); + } + return bitmap; + } + + /** + * 将View转换为byte[]. + * + * @param view 要转换为byte[]的View + * @param compressFormat the compress format + * @return byte[] View图片的byte[] + */ + public static byte[] view2Bytes(View view, Bitmap.CompressFormat compressFormat) { + byte[] b = null; + try { + Bitmap bitmap = AbImageUtil.view2Bitmap(view); + b = AbImageUtil.bitmap2Bytes(bitmap, compressFormat, true); + } catch (Exception e) { + e.printStackTrace(); + } + return b; + } + + /** + * 描述:旋转Bitmap为一定的角度. + * + * @param bitmap the bitmap + * @param degrees the degrees + * @return the bitmap + */ + public static Bitmap rotateBitmap(Bitmap bitmap, float degrees) { + Bitmap mBitmap = null; + try { + Matrix m = new Matrix(); + m.setRotate(degrees % 360); + mBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, false); + } catch (Exception e) { + e.printStackTrace(); + } + return mBitmap; + } + + /** + * 描述:旋转Bitmap为一定的角度并四周暗化处理. + * + * @param bitmap the bitmap + * @param degrees the degrees + * @return the bitmap + */ + public static Bitmap rotateBitmapTranslate(Bitmap bitmap, float degrees) { + Bitmap mBitmap = null; + int width; + int height; + try { + Matrix matrix = new Matrix(); + if ((degrees / 90) % 2 != 0) { + width = bitmap.getWidth(); + height = bitmap.getHeight(); + } else { + width = bitmap.getHeight(); + height = bitmap.getWidth(); + } + int cx = width / 2; + int cy = height / 2; + matrix.preTranslate(-cx, -cy); + matrix.postRotate(degrees); + matrix.postTranslate(cx, cy); + } catch (Exception e) { + e.printStackTrace(); + } + return mBitmap; + } + + /** + * 转换图片转换成圆形. + * + * @param bitmap 传入Bitmap对象 + * @return the bitmap + */ + public static Bitmap toRoundBitmap(Bitmap bitmap) { + if (bitmap == null) { + return null; + } + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + float roundPx; + float left, top, right, bottom, dst_left, dst_top, dst_right, dst_bottom; + if (width <= height) { + roundPx = width / 2; + top = 0; + bottom = width; + left = 0; + right = width; + height = width; + dst_left = 0; + dst_top = 0; + dst_right = width; + dst_bottom = width; + } else { + roundPx = height / 2; + float clip = (width - height) / 2; + left = clip; + right = width - clip; + top = 0; + bottom = height; + width = height; + dst_left = 0; + dst_top = 0; + dst_right = height; + dst_bottom = height; + } + + Bitmap output = Bitmap.createBitmap(width, height, Config.ARGB_8888); + Canvas canvas = new Canvas(output); + final int color = 0xff424242; + final Paint paint = new Paint(); + final Rect src = new Rect((int) left, (int) top, (int) right, (int) bottom); + final Rect dst = new Rect((int) dst_left, (int) dst_top, (int) dst_right, (int) dst_bottom); + final RectF rectF = new RectF(dst); + paint.setAntiAlias(true); + canvas.drawARGB(0, 0, 0, 0); + paint.setColor(color); + canvas.drawRoundRect(rectF, roundPx, roundPx, paint); + paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); + canvas.drawBitmap(bitmap, src, dst, paint); + return output; + } + + + + public static byte[] imagePathToByte(String path) { + byte[] data = null; + FileInputStream input = null; + try { + input = new FileInputStream(new File(path)); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + byte[] buf = new byte[1024]; + int numBytesRead = 0; + while ((numBytesRead = input.read(buf)) != -1) { + output.write(buf, 0, numBytesRead); + } + data = output.toByteArray(); + output.close(); + input.close(); + } catch (FileNotFoundException ex1) { + ex1.printStackTrace(); + } catch (IOException ex1) { + ex1.printStackTrace(); + } + return data; + } + + + + /** + * @param bitmap 原图 + * @param edgeLength 希望得到的正方形部分的边长 + * @return 缩放截取正中部分后的位图。 + */ + public static Bitmap centerSquareScaleBitmap(Bitmap bitmap, int edgeLength) { + if (null == bitmap || edgeLength <= 0) { + return null; + } + + Bitmap result = bitmap; + int widthOrg = bitmap.getWidth(); + int heightOrg = bitmap.getHeight(); + + if (widthOrg > edgeLength && heightOrg > edgeLength) { + // 压缩到一个最小长度是edgeLength的bitmap + int longerEdge = edgeLength * Math.max(widthOrg, heightOrg) / Math.min(widthOrg, heightOrg); + int scaledWidth = widthOrg > heightOrg ? longerEdge : edgeLength; + int scaledHeight = widthOrg > heightOrg ? edgeLength : longerEdge; + Bitmap scaledBitmap; + + try { + scaledBitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, true); + } catch (Exception e) { + return null; + } + + // 从图中截取正中间的正方形部分。 + int xTopLeft = (scaledWidth - edgeLength) / 2; + int yTopLeft = (scaledHeight - edgeLength) / 2; + + try { + result = Bitmap.createBitmap(scaledBitmap, xTopLeft, yTopLeft, edgeLength, edgeLength); + scaledBitmap.recycle(); + } catch (Exception e) { + return null; + } + } + return result; + } + + /** + * @param bitmap 原图 + * @param edgeLength 希望得到的正方形部分的边长 + * @return 缩放截取上面部分后的位图。 + */ + public static Bitmap topSquareScaleBitmap(Bitmap bitmap, int edgeLength) { + if (null == bitmap || edgeLength <= 0) { + return null; + } + + Bitmap result = bitmap; + int widthOrg = bitmap.getWidth(); + int heightOrg = bitmap.getHeight(); + + if (widthOrg > edgeLength && heightOrg > edgeLength) { + // 压缩到一个最小长度是edgeLength的bitmap + int longerEdge = edgeLength * Math.max(widthOrg, heightOrg) / Math.min(widthOrg, heightOrg); + int scaledWidth = widthOrg > heightOrg ? longerEdge : edgeLength; + int scaledHeight = widthOrg > heightOrg ? edgeLength : longerEdge; + Bitmap scaledBitmap; + + try { + scaledBitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, true); + } catch (Exception e) { + return null; + } + + // 从图中截取正中间的正方形部分。 + int xTopLeft = (scaledWidth - edgeLength) / 2; + // int yTopLeft = (scaledHeight - edgeLength) / 2; + int yTopLeft = 0; + + try { + result = Bitmap.createBitmap(scaledBitmap, xTopLeft, yTopLeft, edgeLength, edgeLength); + scaledBitmap.recycle(); + } catch (Exception e) { + return null; + } + } + return result; + } + + /** + * 转换Resources图片转换成Bitmap. + */ + public static Bitmap ResourcesToBitmap(Resources resId) { + Bitmap bmp = BitmapFactory.decodeResource(resId, R.mipmap.ic_launcher); + return bmp; + } + /** + * bitmap转为base64 + * @param bitmap + * @return + */ + public static String bitmapToBase64(Bitmap bitmap) { + + String result = null; + ByteArrayOutputStream baos = null; + try { + if (bitmap != null) { + baos = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); + + baos.flush(); + baos.close(); + + byte[] bitmapBytes = baos.toByteArray(); + result ="data:image/jpg;base64," + Base64.encodeToString(bitmapBytes, Base64.DEFAULT); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (baos != null) { + baos.flush(); + baos.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return result; + } + + /** + * base64转为bitmap + * @param base64Data + * @return + */ + public static Bitmap base64ToBitmap(String base64Data) { + byte[] bytes = Base64.decode(base64Data, Base64.DEFAULT); + return BitmapFactory.decodeByteArray(bytes, 0, bytes.length); + } + /** + * bitmap转成string + * + * @param bitmap + * @return + */ + public static String bitmapToString(Bitmap bitmap) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream();// outputstream + bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); + byte[] appicon = baos.toByteArray();// 转为byte数组 + return Base64.encodeToString(appicon, Base64.DEFAULT); + + } + + /** + * string转成bitmap + * + * @param st + */ + public static Bitmap stringToBitmap(String st) + { + Bitmap bitmap = null; + try + { + byte[] bitmapArray; + bitmapArray = Base64.decode(st, Base64.DEFAULT); + bitmap = + BitmapFactory.decodeByteArray(bitmapArray, 0, + bitmapArray.length); + return bitmap; + } + catch (Exception e) + { + return null; + } + } +} diff --git a/app/src/main/java/com/fenghoo/seven/utils/CloseUtils.java b/app/src/main/java/com/fenghoo/seven/utils/CloseUtils.java new file mode 100644 index 0000000..f6c62d9 --- /dev/null +++ b/app/src/main/java/com/fenghoo/seven/utils/CloseUtils.java @@ -0,0 +1,54 @@ +package com.fenghoo.seven.utils; + +import java.io.Closeable; +import java.io.IOException; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2016/10/09
+ *     desc  : 关闭相关工具类
+ * 
+ */ +public final class CloseUtils { + + private CloseUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * 关闭IO + * + * @param closeables closeables + */ + public static void closeIO(final Closeable... closeables) { + if (closeables == null) return; + for (Closeable closeable : closeables) { + if (closeable != null) { + try { + closeable.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + /** + * 安静关闭IO + * + * @param closeables closeables + */ + public static void closeIOQuietly(final Closeable... closeables) { + if (closeables == null) return; + for (Closeable closeable : closeables) { + if (closeable != null) { + try { + closeable.close(); + } catch (IOException ignored) { + } + } + } + } +} diff --git a/app/src/main/java/com/fenghoo/seven/utils/FileIOUtils.java b/app/src/main/java/com/fenghoo/seven/utils/FileIOUtils.java new file mode 100644 index 0000000..e689ede --- /dev/null +++ b/app/src/main/java/com/fenghoo/seven/utils/FileIOUtils.java @@ -0,0 +1,674 @@ +package com.fenghoo.seven.utils; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.List; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2017/06/22
+ *     desc  : 文件读写相关工具类
+ * 
+ */ +public final class FileIOUtils { + + private FileIOUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + private static final String LINE_SEP = System.getProperty("line.separator"); + + private static int sBufferSize = 8192; + + /** + * 将输入流写入文件 + * + * @param filePath 路径 + * @param is 输入流 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromIS(final String filePath, final InputStream is) { + return writeFileFromIS(getFileByPath(filePath), is, false); + } + + /** + * 将输入流写入文件 + * + * @param filePath 路径 + * @param is 输入流 + * @param append 是否追加在文件末 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromIS(final String filePath, final InputStream is, final boolean append) { + return writeFileFromIS(getFileByPath(filePath), is, append); + } + + /** + * 将输入流写入文件 + * + * @param file 文件 + * @param is 输入流 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromIS(final File file, final InputStream is) { + return writeFileFromIS(file, is, false); + } + + /** + * 将输入流写入文件 + * + * @param file 文件 + * @param is 输入流 + * @param append 是否追加在文件末 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromIS(final File file, final InputStream is, final boolean append) { + if (!createOrExistsFile(file) || is == null) return false; + OutputStream os = null; + try { + os = new BufferedOutputStream(new FileOutputStream(file, append)); + byte data[] = new byte[sBufferSize]; + int len; + while ((len = is.read(data, 0, sBufferSize)) != -1) { + os.write(data, 0, len); + } + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } finally { + CloseUtils.closeIO(is, os); + } + } + + /** + * 将字节数组写入文件 + * + * @param filePath 文件路径 + * @param bytes 字节数组 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByStream(final String filePath, final byte[] bytes) { + return writeFileFromBytesByStream(getFileByPath(filePath), bytes, false); + } + + /** + * 将字节数组写入文件 + * + * @param filePath 文件路径 + * @param bytes 字节数组 + * @param append 是否追加在文件末 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByStream(final String filePath, final byte[] bytes, final boolean append) { + return writeFileFromBytesByStream(getFileByPath(filePath), bytes, append); + } + + /** + * 将字节数组写入文件 + * + * @param file 文件 + * @param bytes 字节数组 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByStream(final File file, final byte[] bytes) { + return writeFileFromBytesByStream(file, bytes, false); + } + + /** + * 将字节数组写入文件 + * + * @param file 文件 + * @param bytes 字节数组 + * @param append 是否追加在文件末 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByStream(final File file, final byte[] bytes, final boolean append) { + if (bytes == null || !createOrExistsFile(file)) return false; + BufferedOutputStream bos = null; + try { + bos = new BufferedOutputStream(new FileOutputStream(file, append)); + bos.write(bytes); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } finally { + CloseUtils.closeIO(bos); + } + } + + /** + * 将字节数组写入文件 + * + * @param filePath 文件路径 + * @param bytes 字节数组 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByChannel(final String filePath, final byte[] bytes, final boolean isForce) { + return writeFileFromBytesByChannel(getFileByPath(filePath), bytes, false, isForce); + } + + /** + * 将字节数组写入文件 + * + * @param filePath 文件路径 + * @param bytes 字节数组 + * @param append 是否追加在文件末 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByChannel(final String filePath, final byte[] bytes, final boolean append, final boolean isForce) { + return writeFileFromBytesByChannel(getFileByPath(filePath), bytes, append, isForce); + } + + /** + * 将字节数组写入文件 + * + * @param file 文件 + * @param bytes 字节数组 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByChannel(final File file, final byte[] bytes, final boolean isForce) { + return writeFileFromBytesByChannel(file, bytes, false, isForce); + } + + /** + * 将字节数组写入文件 + * + * @param file 文件 + * @param bytes 字节数组 + * @param append 是否追加在文件末 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByChannel(final File file, final byte[] bytes, final boolean append, final boolean isForce) { + if (bytes == null) return false; + FileChannel fc = null; + try { + fc = new FileOutputStream(file, append).getChannel(); + fc.position(fc.size()); + fc.write(ByteBuffer.wrap(bytes)); + if (isForce) fc.force(true); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } finally { + CloseUtils.closeIO(fc); + } + } + + /** + * 将字节数组写入文件 + * + * @param filePath 文件路径 + * @param bytes 字节数组 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByMap(final String filePath, final byte[] bytes, final boolean isForce) { + return writeFileFromBytesByMap(filePath, bytes, false, isForce); + } + + /** + * 将字节数组写入文件 + * + * @param filePath 文件路径 + * @param bytes 字节数组 + * @param append 是否追加在文件末 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByMap(final String filePath, final byte[] bytes, final boolean append, final boolean isForce) { + return writeFileFromBytesByMap(getFileByPath(filePath), bytes, append, isForce); + } + + /** + * 将字节数组写入文件 + * + * @param file 文件 + * @param bytes 字节数组 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByMap(final File file, final byte[] bytes, final boolean isForce) { + return writeFileFromBytesByMap(file, bytes, false, isForce); + } + + /** + * 将字节数组写入文件 + * + * @param file 文件 + * @param bytes 字节数组 + * @param append 是否追加在文件末 + * @param isForce 是否写入文件 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromBytesByMap(final File file, final byte[] bytes, final boolean append, final boolean isForce) { + if (bytes == null || !createOrExistsFile(file)) return false; + FileChannel fc = null; + try { + fc = new FileOutputStream(file, append).getChannel(); + MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, fc.size(), bytes.length); + mbb.put(bytes); + if (isForce) mbb.force(); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } finally { + CloseUtils.closeIO(fc); + } + } + + /** + * 将字符串写入文件 + * + * @param filePath 文件路径 + * @param content 写入内容 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromString(final String filePath, final String content) { + return writeFileFromString(getFileByPath(filePath), content, false); + } + + /** + * 将字符串写入文件 + * + * @param filePath 文件路径 + * @param content 写入内容 + * @param append 是否追加在文件末 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromString(final String filePath, final String content, final boolean append) { + return writeFileFromString(getFileByPath(filePath), content, append); + } + + /** + * 将字符串写入文件 + * + * @param file 文件 + * @param content 写入内容 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromString(final File file, final String content) { + return writeFileFromString(file, content, false); + } + + /** + * 将字符串写入文件 + * + * @param file 文件 + * @param content 写入内容 + * @param append 是否追加在文件末 + * @return {@code true}: 写入成功
{@code false}: 写入失败 + */ + public static boolean writeFileFromString(final File file, final String content, final boolean append) { + if (file == null || content == null) return false; + if (!createOrExistsFile(file)) return false; + BufferedWriter bw = null; + try { + bw = new BufferedWriter(new FileWriter(file, append)); + bw.write(content); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } finally { + CloseUtils.closeIO(bw); + } + } + + /////////////////////////////////////////////////////////////////////////// + // the divide line of write and read + /////////////////////////////////////////////////////////////////////////// + + /** + * 读取文件到字符串链表中 + * + * @param filePath 文件路径 + * @return 字符串链表中 + */ + public static List readFile2List(final String filePath) { + return readFile2List(getFileByPath(filePath), null); + } + + /** + * 读取文件到字符串链表中 + * + * @param filePath 文件路径 + * @param charsetName 编码格式 + * @return 字符串链表中 + */ + public static List readFile2List(final String filePath, final String charsetName) { + return readFile2List(getFileByPath(filePath), charsetName); + } + + /** + * 读取文件到字符串链表中 + * + * @param file 文件 + * @return 字符串链表中 + */ + public static List readFile2List(final File file) { + return readFile2List(file, 0, 0x7FFFFFFF, null); + } + + /** + * 读取文件到字符串链表中 + * + * @param file 文件 + * @param charsetName 编码格式 + * @return 字符串链表中 + */ + public static List readFile2List(final File file, final String charsetName) { + return readFile2List(file, 0, 0x7FFFFFFF, charsetName); + } + + /** + * 读取文件到字符串链表中 + * + * @param filePath 文件路径 + * @param st 需要读取的开始行数 + * @param end 需要读取的结束行数 + * @return 字符串链表中 + */ + public static List readFile2List(final String filePath, final int st, final int end) { + return readFile2List(getFileByPath(filePath), st, end, null); + } + + /** + * 读取文件到字符串链表中 + * + * @param filePath 文件路径 + * @param st 需要读取的开始行数 + * @param end 需要读取的结束行数 + * @param charsetName 编码格式 + * @return 字符串链表中 + */ + public static List readFile2List(final String filePath, final int st, final int end, final String charsetName) { + return readFile2List(getFileByPath(filePath), st, end, charsetName); + } + + /** + * 读取文件到字符串链表中 + * + * @param file 文件 + * @param st 需要读取的开始行数 + * @param end 需要读取的结束行数 + * @return 字符串链表中 + */ + public static List readFile2List(final File file, final int st, final int end) { + return readFile2List(file, st, end, null); + } + + /** + * 读取文件到字符串链表中 + * + * @param file 文件 + * @param st 需要读取的开始行数 + * @param end 需要读取的结束行数 + * @param charsetName 编码格式 + * @return 字符串链表中 + */ + public static List readFile2List(final File file, final int st, final int end, final String charsetName) { + if (!isFileExists(file)) return null; + if (st > end) return null; + BufferedReader reader = null; + try { + String line; + int curLine = 1; + List list = new ArrayList<>(); + if (isSpace(charsetName)) { + reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); + } else { + reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charsetName)); + } + while ((line = reader.readLine()) != null) { + if (curLine > end) break; + if (st <= curLine && curLine <= end) list.add(line); + ++curLine; + } + return list; + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + CloseUtils.closeIO(reader); + } + } + + /** + * 读取文件到字符串中 + * + * @param filePath 文件路径 + * @return 字符串 + */ + public static String readFile2String(final String filePath) { + return readFile2String(getFileByPath(filePath), null); + } + + /** + * 读取文件到字符串中 + * + * @param filePath 文件路径 + * @param charsetName 编码格式 + * @return 字符串 + */ + public static String readFile2String(final String filePath, final String charsetName) { + return readFile2String(getFileByPath(filePath), charsetName); + } + + /** + * 读取文件到字符串中 + * + * @param file 文件 + * @return 字符串 + */ + public static String readFile2String(final File file) { + return readFile2String(file, null); + } + + /** + * 读取文件到字符串中 + * + * @param file 文件 + * @param charsetName 编码格式 + * @return 字符串 + */ + public static String readFile2String(final File file, final String charsetName) { + if (!isFileExists(file)) return null; + BufferedReader reader = null; + try { + StringBuilder sb = new StringBuilder(); + if (isSpace(charsetName)) { + reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); + } else { + reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charsetName)); + } + String line; + while ((line = reader.readLine()) != null) { + sb.append(line).append(LINE_SEP); + } + // delete the last line separator + return sb.delete(sb.length() - LINE_SEP.length(), sb.length()).toString(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + CloseUtils.closeIO(reader); + } + } + + /** + * 读取文件到字节数组中 + * + * @param filePath 文件路径 + * @return 字符数组 + */ + public static byte[] readFile2BytesByStream(final String filePath) { + return readFile2BytesByStream(getFileByPath(filePath)); + } + + /** + * 读取文件到字节数组中 + * + * @param file 文件 + * @return 字符数组 + */ + public static byte[] readFile2BytesByStream(final File file) { + if (!isFileExists(file)) return null; + FileInputStream fis = null; + ByteArrayOutputStream os = null; + try { + fis = new FileInputStream(file); + os = new ByteArrayOutputStream(); + byte[] b = new byte[sBufferSize]; + int len; + while ((len = fis.read(b, 0, sBufferSize)) != -1) { + os.write(b, 0, len); + } + return os.toByteArray(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + CloseUtils.closeIO(fis, os); + } + } + + /** + * 读取文件到字节数组中 + * + * @param filePath 文件路径 + * @return 字符数组 + */ + public static byte[] readFile2BytesByChannel(final String filePath) { + return readFile2BytesByChannel(getFileByPath(filePath)); + } + + /** + * 读取文件到字节数组中 + * + * @param file 文件 + * @return 字符数组 + */ + public static byte[] readFile2BytesByChannel(final File file) { + if (!isFileExists(file)) return null; + FileChannel fc = null; + try { + fc = new RandomAccessFile(file, "r").getChannel(); + ByteBuffer byteBuffer = ByteBuffer.allocate((int) fc.size()); + while (true) { + if (!((fc.read(byteBuffer)) > 0)) break; + } + return byteBuffer.array(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + CloseUtils.closeIO(fc); + } + } + + /** + * 读取文件到字节数组中 + * + * @param filePath 文件路径 + * @return 字符数组 + */ + public static byte[] readFile2BytesByMap(final String filePath) { + return readFile2BytesByMap(getFileByPath(filePath)); + } + + /** + * 读取文件到字节数组中 + * + * @param file 文件 + * @return 字符数组 + */ + public static byte[] readFile2BytesByMap(final File file) { + if (!isFileExists(file)) return null; + FileChannel fc = null; + try { + fc = new RandomAccessFile(file, "r").getChannel(); + int size = (int) fc.size(); + MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, size).load(); + byte[] result = new byte[size]; + mbb.get(result, 0, size); + return result; + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + CloseUtils.closeIO(fc); + } + } + + /** + * 设置缓冲区尺寸 + * + * @param bufferSize 缓冲区大小 + */ + public static void setBufferSize(final int bufferSize) { + sBufferSize = bufferSize; + } + + private static File getFileByPath(final String filePath) { + return isSpace(filePath) ? null : new File(filePath); + } + + private static boolean createOrExistsFile(final String filePath) { + return createOrExistsFile(getFileByPath(filePath)); + } + + private static boolean createOrExistsFile(final File file) { + if (file == null) return false; + if (file.exists()) return file.isFile(); + if (!createOrExistsDir(file.getParentFile())) return false; + try { + return file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + private static boolean createOrExistsDir(final File file) { + return file != null && (file.exists() ? file.isDirectory() : file.mkdirs()); + } + + private static boolean isFileExists(final File file) { + return file != null && file.exists(); + } + + private static boolean isSpace(final String s) { + if (s == null) return true; + for (int i = 0, len = s.length(); i < len; ++i) { + if (!Character.isWhitespace(s.charAt(i))) { + return false; + } + } + return true; + } +} diff --git a/app/src/main/java/com/fenghoo/seven/utils/FileUtils.java b/app/src/main/java/com/fenghoo/seven/utils/FileUtils.java new file mode 100644 index 0000000..8ff7ee0 --- /dev/null +++ b/app/src/main/java/com/fenghoo/seven/utils/FileUtils.java @@ -0,0 +1,1133 @@ +package com.fenghoo.seven.utils; + +import android.annotation.SuppressLint; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2016/05/03
+ *     desc  : 文件相关工具类
+ * 
+ */ +public final class FileUtils { + + private FileUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + private static final String LINE_SEP = System.getProperty("line.separator"); + + /** + * 根据文件路径获取文件 + * + * @param filePath 文件路径 + * @return 文件 + */ + public static File getFileByPath(final String filePath) { + return isSpace(filePath) ? null : new File(filePath); + } + + /** + * 判断文件是否存在 + * + * @param filePath 文件路径 + * @return {@code true}: 存在
{@code false}: 不存在 + */ + public static boolean isFileExists(final String filePath) { + return isFileExists(getFileByPath(filePath)); + } + + /** + * 判断文件是否存在 + * + * @param file 文件 + * @return {@code true}: 存在
{@code false}: 不存在 + */ + public static boolean isFileExists(final File file) { + return file != null && file.exists(); + } + + /** + * 重命名文件 + * + * @param filePath 文件路径 + * @param newName 新名称 + * @return {@code true}: 重命名成功
{@code false}: 重命名失败 + */ + public static boolean rename(final String filePath, final String newName) { + return rename(getFileByPath(filePath), newName); + } + + /** + * 重命名文件 + * + * @param file 文件 + * @param newName 新名称 + * @return {@code true}: 重命名成功
{@code false}: 重命名失败 + */ + public static boolean rename(final File file, final String newName) { + // 文件为空返回false + if (file == null) return false; + // 文件不存在返回false + if (!file.exists()) return false; + // 新的文件名为空返回false + if (isSpace(newName)) return false; + // 如果文件名没有改变返回true + if (newName.equals(file.getName())) return true; + File newFile = new File(file.getParent() + File.separator + newName); + // 如果重命名的文件已存在返回false + return !newFile.exists() + && file.renameTo(newFile); + } + + /** + * 判断是否是目录 + * + * @param dirPath 目录路径 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isDir(final String dirPath) { + return isDir(getFileByPath(dirPath)); + } + + /** + * 判断是否是目录 + * + * @param file 文件 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isDir(final File file) { + return isFileExists(file) && file.isDirectory(); + } + + /** + * 判断是否是文件 + * + * @param filePath 文件路径 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isFile(final String filePath) { + return isFile(getFileByPath(filePath)); + } + + /** + * 判断是否是文件 + * + * @param file 文件 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isFile(final File file) { + return isFileExists(file) && file.isFile(); + } + + /** + * 判断目录是否存在,不存在则判断是否创建成功 + * + * @param dirPath 目录路径 + * @return {@code true}: 存在或创建成功
{@code false}: 不存在或创建失败 + */ + public static boolean createOrExistsDir(final String dirPath) { + return createOrExistsDir(getFileByPath(dirPath)); + } + + /** + * 判断目录是否存在,不存在则判断是否创建成功 + * + * @param file 文件 + * @return {@code true}: 存在或创建成功
{@code false}: 不存在或创建失败 + */ + public static boolean createOrExistsDir(final File file) { + // 如果存在,是目录则返回true,是文件则返回false,不存在则返回是否创建成功 + return file != null && (file.exists() ? file.isDirectory() : file.mkdirs()); + } + + /** + * 判断文件是否存在,不存在则判断是否创建成功 + * + * @param filePath 文件路径 + * @return {@code true}: 存在或创建成功
{@code false}: 不存在或创建失败 + */ + public static boolean createOrExistsFile(final String filePath) { + return createOrExistsFile(getFileByPath(filePath)); + } + + /** + * 判断文件是否存在,不存在则判断是否创建成功 + * + * @param file 文件 + * @return {@code true}: 存在或创建成功
{@code false}: 不存在或创建失败 + */ + public static boolean createOrExistsFile(final File file) { + if (file == null) return false; + // 如果存在,是文件则返回true,是目录则返回false + if (file.exists()) return file.isFile(); + if (!createOrExistsDir(file.getParentFile())) return false; + try { + return file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + /** + * 判断文件是否存在,存在则在创建之前删除 + * + * @param file 文件 + * @return {@code true}: 创建成功
{@code false}: 创建失败 + */ + public static boolean createFileByDeleteOldFile(final File file) { + if (file == null) return false; + // 文件存在并且删除失败返回false + if (file.exists() && !file.delete()) return false; + // 创建目录失败返回false + if (!createOrExistsDir(file.getParentFile())) return false; + try { + return file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + /** + * 复制或移动目录 + * + * @param srcDirPath 源目录路径 + * @param destDirPath 目标目录路径 + * @param isMove 是否移动 + * @return {@code true}: 复制或移动成功
{@code false}: 复制或移动失败 + */ + private static boolean copyOrMoveDir(final String srcDirPath, final String destDirPath, final boolean isMove) { + return copyOrMoveDir(getFileByPath(srcDirPath), getFileByPath(destDirPath), isMove); + } + + /** + * 复制或移动目录 + * + * @param srcDir 源目录 + * @param destDir 目标目录 + * @param isMove 是否移动 + * @return {@code true}: 复制或移动成功
{@code false}: 复制或移动失败 + */ + private static boolean copyOrMoveDir(final File srcDir, final File destDir, final boolean isMove) { + if (srcDir == null || destDir == null) return false; + // 如果目标目录在源目录中则返回false,看不懂的话好好想想递归怎么结束 + // srcPath : F:\\MyGithub\\AndroidUtilCode\\utilcode\\src\\test\\res + // destPath: F:\\MyGithub\\AndroidUtilCode\\utilcode\\src\\test\\res1 + // 为防止以上这种情况出现出现误判,须分别在后面加个路径分隔符 + String srcPath = srcDir.getPath() + File.separator; + String destPath = destDir.getPath() + File.separator; + if (destPath.contains(srcPath)) return false; + // 源文件不存在或者不是目录则返回false + if (!srcDir.exists() || !srcDir.isDirectory()) return false; + // 目标目录不存在返回false + if (!createOrExistsDir(destDir)) return false; + File[] files = srcDir.listFiles(); + for (File file : files) { + File oneDestFile = new File(destPath + file.getName()); + if (file.isFile()) { + // 如果操作失败返回false + if (!copyOrMoveFile(file, oneDestFile, isMove)) return false; + } else if (file.isDirectory()) { + // 如果操作失败返回false + if (!copyOrMoveDir(file, oneDestFile, isMove)) return false; + } + } + return !isMove || deleteDir(srcDir); + } + + /** + * 复制或移动文件 + * + * @param srcFilePath 源文件路径 + * @param destFilePath 目标文件路径 + * @param isMove 是否移动 + * @return {@code true}: 复制或移动成功
{@code false}: 复制或移动失败 + */ + private static boolean copyOrMoveFile(final String srcFilePath, final String destFilePath, final boolean isMove) { + return copyOrMoveFile(getFileByPath(srcFilePath), getFileByPath(destFilePath), isMove); + } + + /** + * 复制或移动文件 + * + * @param srcFile 源文件 + * @param destFile 目标文件 + * @param isMove 是否移动 + * @return {@code true}: 复制或移动成功
{@code false}: 复制或移动失败 + */ + private static boolean copyOrMoveFile(final File srcFile, final File destFile, final boolean isMove) { + if (srcFile == null || destFile == null) return false; + // 源文件不存在或者不是文件则返回false + if (!srcFile.exists() || !srcFile.isFile()) return false; + // 目标文件存在且是文件则返回false + if (destFile.exists() && destFile.isFile()) return false; + // 目标目录不存在返回false + if (!createOrExistsDir(destFile.getParentFile())) return false; + try { + return FileIOUtils.writeFileFromIS(destFile, new FileInputStream(srcFile), false) + && !(isMove && !deleteFile(srcFile)); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return false; + } + } + + /** + * 复制目录 + * + * @param srcDirPath 源目录路径 + * @param destDirPath 目标目录路径 + * @return {@code true}: 复制成功
{@code false}: 复制失败 + */ + public static boolean copyDir(final String srcDirPath, final String destDirPath) { + return copyDir(getFileByPath(srcDirPath), getFileByPath(destDirPath)); + } + + /** + * 复制目录 + * + * @param srcDir 源目录 + * @param destDir 目标目录 + * @return {@code true}: 复制成功
{@code false}: 复制失败 + */ + public static boolean copyDir(final File srcDir, final File destDir) { + return copyOrMoveDir(srcDir, destDir, false); + } + + /** + * 复制文件 + * + * @param srcFilePath 源文件路径 + * @param destFilePath 目标文件路径 + * @return {@code true}: 复制成功
{@code false}: 复制失败 + */ + public static boolean copyFile(final String srcFilePath, final String destFilePath) { + return copyFile(getFileByPath(srcFilePath), getFileByPath(destFilePath)); + } + + /** + * 复制文件 + * + * @param srcFile 源文件 + * @param destFile 目标文件 + * @return {@code true}: 复制成功
{@code false}: 复制失败 + */ + public static boolean copyFile(final File srcFile, final File destFile) { + return copyOrMoveFile(srcFile, destFile, false); + } + + /** + * 移动目录 + * + * @param srcDirPath 源目录路径 + * @param destDirPath 目标目录路径 + * @return {@code true}: 移动成功
{@code false}: 移动失败 + */ + public static boolean moveDir(final String srcDirPath, final String destDirPath) { + return moveDir(getFileByPath(srcDirPath), getFileByPath(destDirPath)); + } + + /** + * 移动目录 + * + * @param srcDir 源目录 + * @param destDir 目标目录 + * @return {@code true}: 移动成功
{@code false}: 移动失败 + */ + public static boolean moveDir(final File srcDir, final File destDir) { + return copyOrMoveDir(srcDir, destDir, true); + } + + /** + * 移动文件 + * + * @param srcFilePath 源文件路径 + * @param destFilePath 目标文件路径 + * @return {@code true}: 移动成功
{@code false}: 移动失败 + */ + public static boolean moveFile(final String srcFilePath, final String destFilePath) { + return moveFile(getFileByPath(srcFilePath), getFileByPath(destFilePath)); + } + + /** + * 移动文件 + * + * @param srcFile 源文件 + * @param destFile 目标文件 + * @return {@code true}: 移动成功
{@code false}: 移动失败 + */ + public static boolean moveFile(final File srcFile, final File destFile) { + return copyOrMoveFile(srcFile, destFile, true); + } + + /** + * 删除目录 + * + * @param dirPath 目录路径 + * @return {@code true}: 删除成功
{@code false}: 删除失败 + */ + public static boolean deleteDir(final String dirPath) { + return deleteDir(getFileByPath(dirPath)); + } + + /** + * 删除目录 + * + * @param dir 目录 + * @return {@code true}: 删除成功
{@code false}: 删除失败 + */ + public static boolean deleteDir(final File dir) { + if (dir == null) return false; + // 目录不存在返回true + if (!dir.exists()) return true; + // 不是目录返回false + if (!dir.isDirectory()) return false; + // 现在文件存在且是文件夹 + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (file.isFile()) { + if (!file.delete()) return false; + } else if (file.isDirectory()) { + if (!deleteDir(file)) return false; + } + } + } + return dir.delete(); + } + + /** + * 删除文件 + * + * @param srcFilePath 文件路径 + * @return {@code true}: 删除成功
{@code false}: 删除失败 + */ + public static boolean deleteFile(final String srcFilePath) { + return deleteFile(getFileByPath(srcFilePath)); + } + + /** + * 删除文件 + * + * @param file 文件 + * @return {@code true}: 删除成功
{@code false}: 删除失败 + */ + public static boolean deleteFile(final File file) { + return file != null && (!file.exists() || file.isFile() && file.delete()); + } + + /** + * 删除目录下的所有文件 + * + * @param dirPath 目录路径 + * @return {@code true}: 删除成功
{@code false}: 删除失败 + */ + public static boolean deleteFilesInDir(final String dirPath) { + return deleteFilesInDir(getFileByPath(dirPath)); + } + + /** + * 删除目录下的所有文件 + * + * @param dir 目录 + * @return {@code true}: 删除成功
{@code false}: 删除失败 + */ + public static boolean deleteFilesInDir(final File dir) { + if (dir == null) return false; + // 目录不存在返回true + if (!dir.exists()) return true; + // 不是目录返回false + if (!dir.isDirectory()) return false; + // 现在文件存在且是文件夹 + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (file.isFile()) { + if (!file.delete()) return false; + } else if (file.isDirectory()) { + if (!deleteDir(file)) return false; + } + } + } + return true; + } + + /** + * 获取目录下所有文件 + * + * @param dirPath 目录路径 + * @param isRecursive 是否递归进子目录 + * @return 文件链表 + */ + public static List listFilesInDir(final String dirPath, final boolean isRecursive) { + return listFilesInDir(getFileByPath(dirPath), isRecursive); + } + + /** + * 获取目录下所有文件 + * + * @param dir 目录 + * @param isRecursive 是否递归进子目录 + * @return 文件链表 + */ + public static List listFilesInDir(final File dir, final boolean isRecursive) { + if (!isDir(dir)) return null; + if (isRecursive) return listFilesInDir(dir); + List list = new ArrayList<>(); + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + Collections.addAll(list, files); + } + return list; + } + + /** + * 获取目录下所有文件包括子目录 + * + * @param dirPath 目录路径 + * @return 文件链表 + */ + public static List listFilesInDir(final String dirPath) { + return listFilesInDir(getFileByPath(dirPath)); + } + + /** + * 获取目录下所有文件包括子目录 + * + * @param dir 目录 + * @return 文件链表 + */ + public static List listFilesInDir(final File dir) { + if (!isDir(dir)) return null; + List list = new ArrayList<>(); + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + list.add(file); + if (file.isDirectory()) { + List fileList = listFilesInDir(file); + if (fileList != null) { + list.addAll(fileList); + } + } + } + } + return list; + } + + /** + * 获取目录下所有后缀名为suffix的文件 + *

大小写忽略

+ * + * @param dirPath 目录路径 + * @param suffix 后缀名 + * @param isRecursive 是否递归进子目录 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final String dirPath, final String suffix, final boolean isRecursive) { + return listFilesInDirWithFilter(getFileByPath(dirPath), suffix, isRecursive); + } + + /** + * 获取目录下所有后缀名为suffix的文件 + *

大小写忽略

+ * + * @param dir 目录 + * @param suffix 后缀名 + * @param isRecursive 是否递归进子目录 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final File dir, final String suffix, final boolean isRecursive) { + if (isRecursive) return listFilesInDirWithFilter(dir, suffix); + if (dir == null || !isDir(dir)) return null; + List list = new ArrayList<>(); + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (file.getName().toUpperCase().endsWith(suffix.toUpperCase())) { + list.add(file); + } + } + } + return list; + } + + /** + * 获取目录下所有后缀名为suffix的文件包括子目录 + *

大小写忽略

+ * + * @param dirPath 目录路径 + * @param suffix 后缀名 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final String dirPath, final String suffix) { + return listFilesInDirWithFilter(getFileByPath(dirPath), suffix); + } + + /** + * 获取目录下所有后缀名为suffix的文件包括子目录 + *

大小写忽略

+ * + * @param dir 目录 + * @param suffix 后缀名 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final File dir, final String suffix) { + if (dir == null || !isDir(dir)) return null; + List list = new ArrayList<>(); + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (file.getName().toUpperCase().endsWith(suffix.toUpperCase())) { + list.add(file); + } + if (file.isDirectory()) { + list.addAll(listFilesInDirWithFilter(file, suffix)); + } + } + } + return list; + } + + /** + * 获取目录下所有符合filter的文件 + * + * @param dirPath 目录路径 + * @param filter 过滤器 + * @param isRecursive 是否递归进子目录 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final String dirPath, final FilenameFilter filter, final boolean isRecursive) { + return listFilesInDirWithFilter(getFileByPath(dirPath), filter, isRecursive); + } + + /** + * 获取目录下所有符合filter的文件 + * + * @param dir 目录 + * @param filter 过滤器 + * @param isRecursive 是否递归进子目录 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final File dir, final FilenameFilter filter, final boolean isRecursive) { + if (isRecursive) return listFilesInDirWithFilter(dir, filter); + if (dir == null || !isDir(dir)) return null; + List list = new ArrayList<>(); + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (filter.accept(file.getParentFile(), file.getName())) { + list.add(file); + } + } + } + return list; + } + + /** + * 获取目录下所有符合filter的文件包括子目录 + * + * @param dirPath 目录路径 + * @param filter 过滤器 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final String dirPath, final FilenameFilter filter) { + return listFilesInDirWithFilter(getFileByPath(dirPath), filter); + } + + /** + * 获取目录下所有符合filter的文件包括子目录 + * + * @param dir 目录 + * @param filter 过滤器 + * @return 文件链表 + */ + public static List listFilesInDirWithFilter(final File dir, final FilenameFilter filter) { + if (dir == null || !isDir(dir)) return null; + List list = new ArrayList<>(); + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (filter.accept(file.getParentFile(), file.getName())) { + list.add(file); + } + if (file.isDirectory()) { + list.addAll(listFilesInDirWithFilter(file, filter)); + } + } + } + return list; + } + + /** + * 获取目录下指定文件名的文件包括子目录 + *

大小写忽略

+ * + * @param dirPath 目录路径 + * @param fileName 文件名 + * @return 文件链表 + */ + public static List searchFileInDir(final String dirPath, final String fileName) { + return searchFileInDir(getFileByPath(dirPath), fileName); + } + + /** + * 获取目录下指定文件名的文件包括子目录 + *

大小写忽略

+ * + * @param dir 目录 + * @param fileName 文件名 + * @return 文件链表 + */ + public static List searchFileInDir(final File dir, final String fileName) { + if (dir == null || !isDir(dir)) return null; + List list = new ArrayList<>(); + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (file.getName().toUpperCase().equals(fileName.toUpperCase())) { + list.add(file); + } + if (file.isDirectory()) { + list.addAll(searchFileInDir(file, fileName)); + } + } + } + return list; + } + + /** + * 获取文件最后修改的毫秒时间戳 + * + * @param filePath 文件路径 + * @return 文件最后修改的毫秒时间戳 + */ + public static long getFileLastModified(final String filePath) { + return getFileLastModified(getFileByPath(filePath)); + } + + /** + * 获取文件最后修改的毫秒时间戳 + * + * @param file 文件 + * @return 文件最后修改的毫秒时间戳 + */ + public static long getFileLastModified(final File file) { + if (file == null) return -1; + return file.lastModified(); + } + + /** + * 简单获取文件编码格式 + * + * @param filePath 文件路径 + * @return 文件编码 + */ + public static String getFileCharsetSimple(final String filePath) { + return getFileCharsetSimple(getFileByPath(filePath)); + } + + /** + * 简单获取文件编码格式 + * + * @param file 文件 + * @return 文件编码 + */ + public static String getFileCharsetSimple(final File file) { + int p = 0; + InputStream is = null; + try { + is = new BufferedInputStream(new FileInputStream(file)); + p = (is.read() << 8) + is.read(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + CloseUtils.closeIO(is); + } + switch (p) { + case 0xefbb: + return "UTF-8"; + case 0xfffe: + return "Unicode"; + case 0xfeff: + return "UTF-16BE"; + default: + return "GBK"; + } + } + + /** + * 获取文件行数 + * + * @param filePath 文件路径 + * @return 文件行数 + */ + public static int getFileLines(final String filePath) { + return getFileLines(getFileByPath(filePath)); + } + + /** + * 获取文件行数 + *

比readLine要快很多

+ * + * @param file 文件 + * @return 文件行数 + */ + public static int getFileLines(final File file) { + int count = 1; + InputStream is = null; + try { + is = new BufferedInputStream(new FileInputStream(file)); + byte[] buffer = new byte[1024]; + int readChars; + if (LINE_SEP.endsWith("\n")) { + while ((readChars = is.read(buffer, 0, 1024)) != -1) { + for (int i = 0; i < readChars; ++i) { + if (buffer[i] == '\n') ++count; + } + } + } else { + while ((readChars = is.read(buffer, 0, 1024)) != -1) { + for (int i = 0; i < readChars; ++i) { + if (buffer[i] == '\r') ++count; + } + } + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + CloseUtils.closeIO(is); + } + return count; + } + + /** + * 获取目录大小 + * + * @param dirPath 目录路径 + * @return 文件大小 + */ + public static String getDirSize(final String dirPath) { + return getDirSize(getFileByPath(dirPath)); + } + + /** + * 获取目录大小 + * + * @param dir 目录 + * @return 文件大小 + */ + public static String getDirSize(final File dir) { + long len = getDirLength(dir); + return len == -1 ? "" : byte2FitMemorySize(len); + } + + /** + * 获取文件大小 + * + * @param filePath 文件路径 + * @return 文件大小 + */ + public static String getFileSize(final String filePath) { + return getFileSize(getFileByPath(filePath)); + } + + /** + * 获取文件大小 + * + * @param file 文件 + * @return 文件大小 + */ + public static String getFileSize(final File file) { + long len = getFileLength(file); + return len == -1 ? "" : byte2FitMemorySize(len); + } + + /** + * 获取目录长度 + * + * @param dirPath 目录路径 + * @return 目录长度 + */ + public static long getDirLength(final String dirPath) { + return getDirLength(getFileByPath(dirPath)); + } + + /** + * 获取目录长度 + * + * @param dir 目录 + * @return 目录长度 + */ + public static long getDirLength(final File dir) { + if (!isDir(dir)) return -1; + long len = 0; + File[] files = dir.listFiles(); + if (files != null && files.length != 0) { + for (File file : files) { + if (file.isDirectory()) { + len += getDirLength(file); + } else { + len += file.length(); + } + } + } + return len; + } + + /** + * 获取文件长度 + * + * @param filePath 文件路径 + * @return 文件长度 + */ + public static long getFileLength(final String filePath) { + return getFileLength(getFileByPath(filePath)); + } + + /** + * 获取文件长度 + * + * @param file 文件 + * @return 文件长度 + */ + public static long getFileLength(final File file) { + if (!isFile(file)) return -1; + return file.length(); + } + + /** + * 获取文件的MD5校验码 + * + * @param filePath 文件路径 + * @return 文件的MD5校验码 + */ + public static String getFileMD5ToString(final String filePath) { + File file = isSpace(filePath) ? null : new File(filePath); + return getFileMD5ToString(file); + } + + /** + * 获取文件的MD5校验码 + * + * @param filePath 文件路径 + * @return 文件的MD5校验码 + */ + public static byte[] getFileMD5(final String filePath) { + File file = isSpace(filePath) ? null : new File(filePath); + return getFileMD5(file); + } + + /** + * 获取文件的MD5校验码 + * + * @param file 文件 + * @return 文件的MD5校验码 + */ + public static String getFileMD5ToString(final File file) { + return bytes2HexString(getFileMD5(file)); + } + + /** + * 获取文件的MD5校验码 + * + * @param file 文件 + * @return 文件的MD5校验码 + */ + public static byte[] getFileMD5(final File file) { + if (file == null) return null; + DigestInputStream dis = null; + try { + FileInputStream fis = new FileInputStream(file); + MessageDigest md = MessageDigest.getInstance("MD5"); + dis = new DigestInputStream(fis, md); + byte[] buffer = new byte[1024 * 256]; + while (true) { + if (!(dis.read(buffer) > 0)) break; + } + md = dis.getMessageDigest(); + return md.digest(); + } catch (NoSuchAlgorithmException | IOException e) { + e.printStackTrace(); + } finally { + CloseUtils.closeIO(dis); + } + return null; + } + + /** + * 获取全路径中的最长目录 + * + * @param file 文件 + * @return filePath最长目录 + */ + public static String getDirName(final File file) { + if (file == null) return null; + return getDirName(file.getPath()); + } + + /** + * 获取全路径中的最长目录 + * + * @param filePath 文件路径 + * @return filePath最长目录 + */ + public static String getDirName(final String filePath) { + if (isSpace(filePath)) return filePath; + int lastSep = filePath.lastIndexOf(File.separator); + return lastSep == -1 ? "" : filePath.substring(0, lastSep + 1); + } + + /** + * 获取全路径中的文件名 + * + * @param file 文件 + * @return 文件名 + */ + public static String getFileName(final File file) { + if (file == null) return null; + return getFileName(file.getPath()); + } + + /** + * 获取全路径中的文件名 + * + * @param filePath 文件路径 + * @return 文件名 + */ + public static String getFileName(final String filePath) { + if (isSpace(filePath)) return filePath; + int lastSep = filePath.lastIndexOf(File.separator); + return lastSep == -1 ? filePath : filePath.substring(lastSep + 1); + } + + /** + * 获取全路径中的不带拓展名的文件名 + * + * @param file 文件 + * @return 不带拓展名的文件名 + */ + public static String getFileNameNoExtension(final File file) { + if (file == null) return null; + return getFileNameNoExtension(file.getPath()); + } + + /** + * 获取全路径中的不带拓展名的文件名 + * + * @param filePath 文件路径 + * @return 不带拓展名的文件名 + */ + public static String getFileNameNoExtension(final String filePath) { + if (isSpace(filePath)) return filePath; + int lastPoi = filePath.lastIndexOf('.'); + int lastSep = filePath.lastIndexOf(File.separator); + if (lastSep == -1) { + return (lastPoi == -1 ? filePath : filePath.substring(0, lastPoi)); + } + if (lastPoi == -1 || lastSep > lastPoi) { + return filePath.substring(lastSep + 1); + } + return filePath.substring(lastSep + 1, lastPoi); + } + + /** + * 获取全路径中的文件拓展名 + * + * @param file 文件 + * @return 文件拓展名 + */ + public static String getFileExtension(final File file) { + if (file == null) return null; + return getFileExtension(file.getPath()); + } + + /** + * 获取全路径中的文件拓展名 + * + * @param filePath 文件路径 + * @return 文件拓展名 + */ + public static String getFileExtension(final String filePath) { + if (isSpace(filePath)) return filePath; + int lastPoi = filePath.lastIndexOf('.'); + int lastSep = filePath.lastIndexOf(File.separator); + if (lastPoi == -1 || lastSep >= lastPoi) return ""; + return filePath.substring(lastPoi + 1); + } + + /////////////////////////////////////////////////////////////////////////// + // copy from ConvertUtils + /////////////////////////////////////////////////////////////////////////// + + private static final char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + /** + * byteArr转hexString + *

例如:

+ * bytes2HexString(new byte[] { 0, (byte) 0xa8 }) returns 00A8 + * + * @param bytes 字节数组 + * @return 16进制大写字符串 + */ + private static String bytes2HexString(final byte[] bytes) { + if (bytes == null) return null; + int len = bytes.length; + if (len <= 0) return null; + char[] ret = new char[len << 1]; + for (int i = 0, j = 0; i < len; i++) { + ret[j++] = hexDigits[bytes[i] >>> 4 & 0x0f]; + ret[j++] = hexDigits[bytes[i] & 0x0f]; + } + return new String(ret); + } + + /** + * 字节数转合适内存大小 + *

保留3位小数

+ * + * @param byteNum 字节数 + * @return 合适内存大小 + */ + @SuppressLint("DefaultLocale") + private static String byte2FitMemorySize(final long byteNum) { + if (byteNum < 0) { + return "shouldn't be less than zero!"; + } else if (byteNum < 1024) { + return String.format("%.3fB", (double) byteNum + 0.0005); + } else if (byteNum < 1048576) { + return String.format("%.3fKB", (double) byteNum / 1024 + 0.0005); + } else if (byteNum < 1073741824) { + return String.format("%.3fMB", (double) byteNum / 1048576 + 0.0005); + } else { + return String.format("%.3fGB", (double) byteNum / 1073741824 + 0.0005); + } + } + + private static boolean isSpace(final String s) { + if (s == null) return true; + for (int i = 0, len = s.length(); i < len; ++i) { + if (!Character.isWhitespace(s.charAt(i))) { + return false; + } + } + return true; + } +} diff --git a/app/src/main/java/com/fenghoo/seven/utils/ImageUtils.java b/app/src/main/java/com/fenghoo/seven/utils/ImageUtils.java new file mode 100644 index 0000000..fa16f1d --- /dev/null +++ b/app/src/main/java/com/fenghoo/seven/utils/ImageUtils.java @@ -0,0 +1,1526 @@ +package com.fenghoo.seven.utils; + +import android.annotation.TargetApi; +import android.graphics.Bitmap; +import android.graphics.Bitmap.CompressFormat; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.media.ExifInterface; +import android.os.Build; +import android.renderscript.Allocation; +import android.renderscript.Element; +import android.renderscript.RenderScript; +import android.renderscript.ScriptIntrinsicBlur; +import android.view.View; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import androidx.annotation.FloatRange; +import androidx.annotation.IntRange; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2016/08/12
+ *     desc  : 图片相关工具类
+ * 
+ */ +public final class ImageUtils { + + private ImageUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * bitmap转byteArr + * + * @param bitmap bitmap对象 + * @param format 格式 + * @return 字节数组 + */ + public static byte[] bitmap2Bytes(final Bitmap bitmap, final CompressFormat format) { + if (bitmap == null) return null; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + bitmap.compress(format, 100, baos); + return baos.toByteArray(); + } + + /** + * byteArr转bitmap + * + * @param bytes 字节数组 + * @return bitmap + */ + public static Bitmap bytes2Bitmap(final byte[] bytes) { + return (bytes == null || bytes.length == 0) ? null : BitmapFactory.decodeByteArray(bytes, 0, bytes.length); + } + + /** + * drawable转bitmap + * + * @param drawable drawable对象 + * @return bitmap + */ + public static Bitmap drawable2Bitmap(final Drawable drawable) { + if (drawable instanceof BitmapDrawable) { + BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; + if (bitmapDrawable.getBitmap() != null) { + return bitmapDrawable.getBitmap(); + } + } + Bitmap bitmap; + if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) { + bitmap = Bitmap.createBitmap(1, 1, + drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); + } else { + bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), + drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); + } + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + return bitmap; + } + + /** + * bitmap转drawable + * + * @param bitmap bitmap对象 + * @return drawable-xxhdpi + */ + public static Drawable bitmap2Drawable(final Bitmap bitmap) { + return bitmap == null ? null : new BitmapDrawable(Utils.getContext().getResources(), bitmap); + } + + /** + * drawable转byteArr + * + * @param drawable drawable对象 + * @param format 格式 + * @return 字节数组 + */ + public static byte[] drawable2Bytes(final Drawable drawable, final CompressFormat format) { + return drawable == null ? null : bitmap2Bytes(drawable2Bitmap(drawable), format); + } + + /** + * byteArr转drawable + * + * @param bytes 字节数组 + * @return drawable-xxhdpi + */ + public static Drawable bytes2Drawable(final byte[] bytes) { + return bitmap2Drawable(bytes2Bitmap(bytes)); + } + + /** + * view转Bitmap + * + * @param view 视图 + * @return bitmap + */ + public static Bitmap view2Bitmap(final View view) { + if (view == null) return null; + Bitmap ret = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(ret); + Drawable bgDrawable = view.getBackground(); + if (bgDrawable != null) { + bgDrawable.draw(canvas); + } else { + canvas.drawColor(Color.WHITE); + } + view.draw(canvas); + return ret; + } + + /** + * 计算采样大小 + * + * @param options 选项 + * @param maxWidth 最大宽度 + * @param maxHeight 最大高度 + * @return 采样大小 + */ + private static int calculateInSampleSize(final BitmapFactory.Options options, final int maxWidth, final int maxHeight) { + if (maxWidth == 0 || maxHeight == 0) return 1; + int height = options.outHeight; + int width = options.outWidth; + int inSampleSize = 1; + while ((height >>= 1) > maxHeight && (width >>= 1) > maxWidth) { + inSampleSize <<= 1; + } + return inSampleSize; + } + + /** + * 获取bitmap + * + * @param file 文件 + * @return bitmap + */ + public static Bitmap getBitmap(final File file) { + if (file == null) return null; + InputStream is = null; + try { + is = new BufferedInputStream(new FileInputStream(file)); + return BitmapFactory.decodeStream(is); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } finally { + CloseUtils.closeIO(is); + } + } + + /** + * 获取bitmap + * + * @param file 文件 + * @param maxWidth 最大宽度 + * @param maxHeight 最大高度 + * @return bitmap + */ + public static Bitmap getBitmap(final File file, final int maxWidth, final int maxHeight) { + if (file == null) return null; + InputStream is = null; + try { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + is = new BufferedInputStream(new FileInputStream(file)); + BitmapFactory.decodeStream(is, null, options); + options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); + options.inJustDecodeBounds = false; + return BitmapFactory.decodeStream(is, null, options); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } finally { + CloseUtils.closeIO(is); + } + } + + /** + * 获取bitmap + * + * @param filePath 文件路径 + * @return bitmap + */ + public static Bitmap getBitmap(final String filePath) { + if (isSpace(filePath)) return null; + return BitmapFactory.decodeFile(filePath); + } + + /** + * 获取bitmap + * + * @param filePath 文件路径 + * @param maxWidth 最大宽度 + * @param maxHeight 最大高度 + * @return bitmap + */ + public static Bitmap getBitmap(final String filePath, final int maxWidth, final int maxHeight) { + if (isSpace(filePath)) return null; + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(filePath, options); + options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); + options.inJustDecodeBounds = false; + return BitmapFactory.decodeFile(filePath, options); + } + + /** + * 获取bitmap + * + * @param is 输入流 + * @return bitmap + */ + public static Bitmap getBitmap(final InputStream is) { + if (is == null) return null; + return BitmapFactory.decodeStream(is); + } + + /** + * 获取bitmap + * + * @param is 输入流 + * @param maxWidth 最大宽度 + * @param maxHeight 最大高度 + * @return bitmap + */ + public static Bitmap getBitmap(final InputStream is, final int maxWidth, final int maxHeight) { + if (is == null) return null; + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeStream(is, null, options); + options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); + options.inJustDecodeBounds = false; + return BitmapFactory.decodeStream(is, null, options); + } + + /** + * 获取bitmap + * + * @param data 数据 + * @param offset 偏移量 + * @return bitmap + */ + public static Bitmap getBitmap(final byte[] data, final int offset) { + if (data.length == 0) return null; + return BitmapFactory.decodeByteArray(data, offset, data.length); + } + + /** + * 获取bitmap + * + * @param data 数据 + * @param offset 偏移量 + * @param maxWidth 最大宽度 + * @param maxHeight 最大高度 + * @return bitmap + */ + public static Bitmap getBitmap(final byte[] data, final int offset, final int maxWidth, final int maxHeight) { + if (data.length == 0) return null; + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeByteArray(data, offset, data.length, options); + options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); + options.inJustDecodeBounds = false; + return BitmapFactory.decodeByteArray(data, offset, data.length, options); + } + + /** + * 获取bitmap + * + * @param id 资源id + * @return bitmap + */ + public static Bitmap getBitmap(final int id) { + return BitmapFactory.decodeResource(Utils.getContext().getResources(), id); + } + + /** + * 获取bitmap + * + * @param id 资源id + * @param maxWidth 最大宽度 + * @param maxHeight 最大高度 + * @return bitmap + */ + public static Bitmap getBitmap(final int id, final int maxWidth, final int maxHeight) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeResource(Utils.getContext().getResources(), id, options); + options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); + options.inJustDecodeBounds = false; + return BitmapFactory.decodeResource(Utils.getContext().getResources(), id, options); + } + + /** + * 获取bitmap + * + * @param fd 文件描述 + * @return bitmap + */ + public static Bitmap getBitmap(final FileDescriptor fd) { + if (fd == null) return null; + return BitmapFactory.decodeFileDescriptor(fd); + } + + /** + * 获取bitmap + * + * @param fd 文件描述 + * @param maxWidth 最大宽度 + * @param maxHeight 最大高度 + * @return bitmap + */ + public static Bitmap getBitmap(final FileDescriptor fd, final int maxWidth, final int maxHeight) { + if (fd == null) return null; + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFileDescriptor(fd, null, options); + options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); + options.inJustDecodeBounds = false; + return BitmapFactory.decodeFileDescriptor(fd, null, options); + } + + /** + * 缩放图片 + * + * @param src 源图片 + * @param newWidth 新宽度 + * @param newHeight 新高度 + * @return 缩放后的图片 + */ + public static Bitmap scale(final Bitmap src, final int newWidth, final int newHeight) { + return scale(src, newWidth, newHeight, false); + } + + /** + * 缩放图片 + * + * @param src 源图片 + * @param newWidth 新宽度 + * @param newHeight 新高度 + * @param recycle 是否回收 + * @return 缩放后的图片 + */ + public static Bitmap scale(final Bitmap src, final int newWidth, final int newHeight, final boolean recycle) { + if (isEmptyBitmap(src)) return null; + Bitmap ret = Bitmap.createScaledBitmap(src, newWidth, newHeight, true); + if (recycle && !src.isRecycled()) src.recycle(); + return ret; + } + + /** + * 缩放图片 + * + * @param src 源图片 + * @param scaleWidth 缩放宽度倍数 + * @param scaleHeight 缩放高度倍数 + * @return 缩放后的图片 + */ + public static Bitmap scale(final Bitmap src, final float scaleWidth, final float scaleHeight) { + return scale(src, scaleWidth, scaleHeight, false); + } + + /** + * 缩放图片 + * + * @param src 源图片 + * @param scaleWidth 缩放宽度倍数 + * @param scaleHeight 缩放高度倍数 + * @param recycle 是否回收 + * @return 缩放后的图片 + */ + public static Bitmap scale(final Bitmap src, final float scaleWidth, final float scaleHeight, final boolean recycle) { + if (isEmptyBitmap(src)) return null; + Matrix matrix = new Matrix(); + matrix.setScale(scaleWidth, scaleHeight); + Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true); + if (recycle && !src.isRecycled()) src.recycle(); + return ret; + } + + /** + * 裁剪图片 + * + * @param src 源图片 + * @param x 开始坐标x + * @param y 开始坐标y + * @param width 裁剪宽度 + * @param height 裁剪高度 + * @return 裁剪后的图片 + */ + public static Bitmap clip(final Bitmap src, final int x, final int y, final int width, final int height) { + return clip(src, x, y, width, height, false); + } + + /** + * 裁剪图片 + * + * @param src 源图片 + * @param x 开始坐标x + * @param y 开始坐标y + * @param width 裁剪宽度 + * @param height 裁剪高度 + * @param recycle 是否回收 + * @return 裁剪后的图片 + */ + public static Bitmap clip(final Bitmap src, final int x, final int y, final int width, final int height, final boolean recycle) { + if (isEmptyBitmap(src)) return null; + Bitmap ret = Bitmap.createBitmap(src, x, y, width, height); + if (recycle && !src.isRecycled()) src.recycle(); + return ret; + } + + /** + * 倾斜图片 + * + * @param src 源图片 + * @param kx 倾斜因子x + * @param ky 倾斜因子y + * @return 倾斜后的图片 + */ + public static Bitmap skew(final Bitmap src, final float kx, final float ky) { + return skew(src, kx, ky, 0, 0, false); + } + + /** + * 倾斜图片 + * + * @param src 源图片 + * @param kx 倾斜因子x + * @param ky 倾斜因子y + * @param recycle 是否回收 + * @return 倾斜后的图片 + */ + public static Bitmap skew(final Bitmap src, final float kx, final float ky, final boolean recycle) { + return skew(src, kx, ky, 0, 0, recycle); + } + + /** + * 倾斜图片 + * + * @param src 源图片 + * @param kx 倾斜因子x + * @param ky 倾斜因子y + * @param px 平移因子x + * @param py 平移因子y + * @return 倾斜后的图片 + */ + public static Bitmap skew(final Bitmap src, final float kx, final float ky, final float px, final float py) { + return skew(src, kx, ky, px, py, false); + } + + /** + * 倾斜图片 + * + * @param src 源图片 + * @param kx 倾斜因子x + * @param ky 倾斜因子y + * @param px 平移因子x + * @param py 平移因子y + * @param recycle 是否回收 + * @return 倾斜后的图片 + */ + public static Bitmap skew(final Bitmap src, final float kx, final float ky, final float px, final float py, final boolean recycle) { + if (isEmptyBitmap(src)) return null; + Matrix matrix = new Matrix(); + matrix.setSkew(kx, ky, px, py); + Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true); + if (recycle && !src.isRecycled()) src.recycle(); + return ret; + } + + /** + * 旋转图片 + * + * @param src 源图片 + * @param degrees 旋转角度 + * @param px 旋转点横坐标 + * @param py 旋转点纵坐标 + * @return 旋转后的图片 + */ + public static Bitmap rotate(final Bitmap src, final int degrees, final float px, final float py) { + return rotate(src, degrees, px, py, false); + } + + /** + * 旋转图片 + * + * @param src 源图片 + * @param degrees 旋转角度 + * @param px 旋转点横坐标 + * @param py 旋转点纵坐标 + * @param recycle 是否回收 + * @return 旋转后的图片 + */ + public static Bitmap rotate(final Bitmap src, final int degrees, final float px, final float py, final boolean recycle) { + if (isEmptyBitmap(src)) return null; + if (degrees == 0) return src; + Matrix matrix = new Matrix(); + matrix.setRotate(degrees, px, py); + Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true); + if (recycle && !src.isRecycled()) src.recycle(); + return ret; + } + + /** + * 获取图片旋转角度 + * + * @param filePath 文件路径 + * @return 旋转角度 + */ + public static int getRotateDegree(final String filePath) { + int degree = 0; + try { + ExifInterface exifInterface = new ExifInterface(filePath); + int orientation = exifInterface.getAttributeInt( + ExifInterface.TAG_ORIENTATION, + ExifInterface.ORIENTATION_NORMAL); + switch (orientation) { + default: + case ExifInterface.ORIENTATION_ROTATE_90: + degree = 90; + break; + case ExifInterface.ORIENTATION_ROTATE_180: + degree = 180; + break; + case ExifInterface.ORIENTATION_ROTATE_270: + degree = 270; + break; + } + } catch (IOException e) { + e.printStackTrace(); + } + return degree; + } + + /** + * 转为圆形图片 + * + * @param src 源图片 + * @return 圆形图片 + */ + public static Bitmap toRound(final Bitmap src) { + return toRound(src, false); + } + + /** + * 转为圆形图片 + * + * @param src 源图片 + * @param recycle 是否回收 + * @return 圆形图片 + */ + public static Bitmap toRound(final Bitmap src, final boolean recycle) { + if (isEmptyBitmap(src)) return null; + int width = src.getWidth(); + int height = src.getHeight(); + int radius = Math.min(width, height) >> 1; + Bitmap ret = Bitmap.createBitmap(width, height, src.getConfig()); + Paint paint = new Paint(); + Canvas canvas = new Canvas(ret); + Rect rect = new Rect(0, 0, width, height); + paint.setAntiAlias(true); + canvas.drawARGB(0, 0, 0, 0); + canvas.drawCircle(width >> 1, height >> 1, radius, paint); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + canvas.drawBitmap(src, rect, rect, paint); + if (recycle && !src.isRecycled()) src.recycle(); + return ret; + } + + /** + * 转为圆角图片 + * + * @param src 源图片 + * @param radius 圆角的度数 + * @return 圆角图片 + */ + public static Bitmap toRoundCorner(final Bitmap src, final float radius) { + return toRoundCorner(src, radius, false); + } + + /** + * 转为圆角图片 + * + * @param src 源图片 + * @param radius 圆角的度数 + * @param recycle 是否回收 + * @return 圆角图片 + */ + public static Bitmap toRoundCorner(final Bitmap src, final float radius, final boolean recycle) { + if (null == src) return null; + int width = src.getWidth(); + int height = src.getHeight(); + Bitmap ret = Bitmap.createBitmap(width, height, src.getConfig()); + Paint paint = new Paint(); + Canvas canvas = new Canvas(ret); + Rect rect = new Rect(0, 0, width, height); + paint.setAntiAlias(true); + canvas.drawRoundRect(new RectF(rect), radius, radius, paint); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + canvas.drawBitmap(src, rect, rect, paint); + if (recycle && !src.isRecycled()) src.recycle(); + return ret; + } + + /** + * 快速模糊 + *

先缩小原图,对小图进行模糊,再放大回原先尺寸

+ * + * @param src 源图片 + * @param scale 缩放比例(0...1) + * @param radius 模糊半径 + * @return 模糊后的图片 + */ + public static Bitmap fastBlur(final Bitmap src, + @FloatRange(from = 0, to = 1, fromInclusive = false) final float scale, + @FloatRange(from = 0, to = 25, fromInclusive = false) final float radius) { + return fastBlur(src, scale, radius, false); + } + + /** + * 快速模糊图片 + *

先缩小原图,对小图进行模糊,再放大回原先尺寸

+ * + * @param src 源图片 + * @param scale 缩放比例(0...1) + * @param radius 模糊半径(0...25) + * @param recycle 是否回收 + * @return 模糊后的图片 + */ + public static Bitmap fastBlur(final Bitmap src, + @FloatRange(from = 0, to = 1, fromInclusive = false) final float scale, + @FloatRange(from = 0, to = 25, fromInclusive = false) final float radius, + boolean recycle) { + if (isEmptyBitmap(src)) return null; + int width = src.getWidth(); + int height = src.getHeight(); + int scaleWidth = (int) (width * scale + 0.5f); + int scaleHeight = (int) (height * scale + 0.5f); + if (scaleWidth == 0 || scaleHeight == 0) return null; + Bitmap scaleBitmap = Bitmap.createScaledBitmap(src, scaleWidth, scaleHeight, true); + Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG); + Canvas canvas = new Canvas(); + PorterDuffColorFilter filter = new PorterDuffColorFilter( + Color.TRANSPARENT, PorterDuff.Mode.SRC_ATOP); + paint.setColorFilter(filter); + canvas.scale(scale, scale); + canvas.drawBitmap(scaleBitmap, 0, 0, paint); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + scaleBitmap = renderScriptBlur(scaleBitmap, radius); + } else { + scaleBitmap = stackBlur(scaleBitmap, (int) radius, recycle); + } + if (scale == 1) return scaleBitmap; + Bitmap ret = Bitmap.createScaledBitmap(scaleBitmap, width, height, true); + if (scaleBitmap != null && !scaleBitmap.isRecycled()) scaleBitmap.recycle(); + if (recycle && !src.isRecycled()) src.recycle(); + return ret; + } + + /** + * renderScript模糊图片 + *

API大于17

+ * + * @param src 源图片 + * @param radius 模糊半径(0...25) + * @return 模糊后的图片 + */ + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) + public static Bitmap renderScriptBlur(final Bitmap src, + @FloatRange(from = 0, to = 25, fromInclusive = false) final float radius) { + if (isEmptyBitmap(src)) return null; + RenderScript rs = null; + try { + rs = RenderScript.create(Utils.getContext()); + rs.setMessageHandler(new RenderScript.RSMessageHandler()); + Allocation input = Allocation.createFromBitmap(rs, src, Allocation.MipmapControl.MIPMAP_NONE, Allocation + .USAGE_SCRIPT); + Allocation output = Allocation.createTyped(rs, input.getType()); + ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); + blurScript.setInput(input); + blurScript.setRadius(radius); + blurScript.forEach(output); + output.copyTo(src); + } finally { + if (rs != null) { + rs.destroy(); + } + } + return src; + } + + /** + * stack模糊图片 + * + * @param src 源图片 + * @param radius 模糊半径 + * @param recycle 是否回收 + * @return stack模糊后的图片 + */ + public static Bitmap stackBlur(final Bitmap src, final int radius, final boolean recycle) { + Bitmap ret; + if (recycle) { + ret = src; + } else { + ret = src.copy(src.getConfig(), true); + } + + if (radius < 1) { + return null; + } + + int w = ret.getWidth(); + int h = ret.getHeight(); + + int[] pix = new int[w * h]; + ret.getPixels(pix, 0, w, 0, 0, w, h); + + int wm = w - 1; + int hm = h - 1; + int wh = w * h; + int div = radius + radius + 1; + + int r[] = new int[wh]; + int g[] = new int[wh]; + int b[] = new int[wh]; + int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; + int vmin[] = new int[Math.max(w, h)]; + + int divsum = (div + 1) >> 1; + divsum *= divsum; + int dv[] = new int[256 * divsum]; + for (i = 0; i < 256 * divsum; i++) { + dv[i] = (i / divsum); + } + + yw = yi = 0; + + int[][] stack = new int[div][3]; + int stackpointer; + int stackstart; + int[] sir; + int rbs; + int r1 = radius + 1; + int routsum, goutsum, boutsum; + int rinsum, ginsum, binsum; + + for (y = 0; y < h; y++) { + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; + for (i = -radius; i <= radius; i++) { + p = pix[yi + Math.min(wm, Math.max(i, 0))]; + sir = stack[i + radius]; + sir[0] = (p & 0xff0000) >> 16; + sir[1] = (p & 0x00ff00) >> 8; + sir[2] = (p & 0x0000ff); + rbs = r1 - Math.abs(i); + rsum += sir[0] * rbs; + gsum += sir[1] * rbs; + bsum += sir[2] * rbs; + if (i > 0) { + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + } else { + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + } + } + stackpointer = radius; + + for (x = 0; x < w; x++) { + + r[yi] = dv[rsum]; + g[yi] = dv[gsum]; + b[yi] = dv[bsum]; + + rsum -= routsum; + gsum -= goutsum; + bsum -= boutsum; + + stackstart = stackpointer - radius + div; + sir = stack[stackstart % div]; + + routsum -= sir[0]; + goutsum -= sir[1]; + boutsum -= sir[2]; + + if (y == 0) { + vmin[x] = Math.min(x + radius + 1, wm); + } + p = pix[yw + vmin[x]]; + + sir[0] = (p & 0xff0000) >> 16; + sir[1] = (p & 0x00ff00) >> 8; + sir[2] = (p & 0x0000ff); + + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + + rsum += rinsum; + gsum += ginsum; + bsum += binsum; + + stackpointer = (stackpointer + 1) % div; + sir = stack[(stackpointer) % div]; + + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + + rinsum -= sir[0]; + ginsum -= sir[1]; + binsum -= sir[2]; + + yi++; + } + yw += w; + } + for (x = 0; x < w; x++) { + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; + yp = -radius * w; + for (i = -radius; i <= radius; i++) { + yi = Math.max(0, yp) + x; + + sir = stack[i + radius]; + + sir[0] = r[yi]; + sir[1] = g[yi]; + sir[2] = b[yi]; + + rbs = r1 - Math.abs(i); + + rsum += r[yi] * rbs; + gsum += g[yi] * rbs; + bsum += b[yi] * rbs; + + if (i > 0) { + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + } else { + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + } + + if (i < hm) { + yp += w; + } + } + yi = x; + stackpointer = radius; + for (y = 0; y < h; y++) { + // Preserve alpha channel: ( 0xff000000 & pix[yi] ) + pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum]; + + rsum -= routsum; + gsum -= goutsum; + bsum -= boutsum; + + stackstart = stackpointer - radius + div; + sir = stack[stackstart % div]; + + routsum -= sir[0]; + goutsum -= sir[1]; + boutsum -= sir[2]; + + if (x == 0) { + vmin[y] = Math.min(y + r1, hm) * w; + } + p = x + vmin[y]; + + sir[0] = r[p]; + sir[1] = g[p]; + sir[2] = b[p]; + + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + + rsum += rinsum; + gsum += ginsum; + bsum += binsum; + + stackpointer = (stackpointer + 1) % div; + sir = stack[stackpointer]; + + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + + rinsum -= sir[0]; + ginsum -= sir[1]; + binsum -= sir[2]; + + yi += w; + } + } + ret.setPixels(pix, 0, w, 0, 0, w, h); + return ret; + } + + /** + * 添加颜色边框 + * + * @param src 源图片 + * @param borderWidth 边框宽度 + * @param color 边框的颜色值 + * @return 带颜色边框图 + */ + public static Bitmap addFrame(final Bitmap src, final int borderWidth, final int color) { + return addFrame(src, borderWidth, color, false); + } + + /** + * 添加颜色边框 + * + * @param src 源图片 + * @param borderWidth 边框宽度 + * @param color 边框的颜色值 + * @param recycle 是否回收 + * @return 带颜色边框图 + */ + public static Bitmap addFrame(final Bitmap src, final int borderWidth, final int color, final boolean recycle) { + if (isEmptyBitmap(src)) return null; + int doubleBorder = borderWidth << 1; + int newWidth = src.getWidth() + doubleBorder; + int newHeight = src.getHeight() + doubleBorder; + Bitmap ret = Bitmap.createBitmap(newWidth, newHeight, src.getConfig()); + Canvas canvas = new Canvas(ret); + //noinspection SuspiciousNameCombination + canvas.drawBitmap(src, borderWidth, borderWidth, null); + Paint paint = new Paint(); + paint.setColor(color); + paint.setStyle(Paint.Style.STROKE); + // setStrokeWidth是居中画的,所以要两倍的宽度才能画,否则有一半的宽度是空的 + paint.setStrokeWidth(doubleBorder); + Rect rect = new Rect(0, 0, newWidth, newHeight); + canvas.drawRect(rect, paint); + if (recycle && !src.isRecycled()) src.recycle(); + return ret; + } + + /** + * 添加倒影 + * + * @param src 源图片的 + * @param reflectionHeight 倒影高度 + * @return 带倒影图片 + */ + public static Bitmap addReflection(final Bitmap src, final int reflectionHeight) { + return addReflection(src, reflectionHeight, false); + } + + /** + * 添加倒影 + * + * @param src 源图片的 + * @param reflectionHeight 倒影高度 + * @param recycle 是否回收 + * @return 带倒影图片 + */ + public static Bitmap addReflection(final Bitmap src, final int reflectionHeight, final boolean recycle) { + if (isEmptyBitmap(src)) return null; + // 原图与倒影之间的间距 + final int REFLECTION_GAP = 0; + int srcWidth = src.getWidth(); + int srcHeight = src.getHeight(); + Matrix matrix = new Matrix(); + matrix.preScale(1, -1); + Bitmap reflectionBitmap = Bitmap.createBitmap(src, 0, srcHeight - reflectionHeight, + srcWidth, reflectionHeight, matrix, false); + Bitmap ret = Bitmap.createBitmap(srcWidth, srcHeight + reflectionHeight, src.getConfig()); + Canvas canvas = new Canvas(ret); + canvas.drawBitmap(src, 0, 0, null); + canvas.drawBitmap(reflectionBitmap, 0, srcHeight + REFLECTION_GAP, null); + Paint paint = new Paint(); + paint.setAntiAlias(true); + LinearGradient shader = new LinearGradient(0, srcHeight, + 0, ret.getHeight() + REFLECTION_GAP, + 0x70FFFFFF, 0x00FFFFFF, Shader.TileMode.MIRROR); + paint.setShader(shader); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); + canvas.drawRect(0, srcHeight + REFLECTION_GAP, + srcWidth, ret.getHeight(), paint); + if (!reflectionBitmap.isRecycled()) reflectionBitmap.recycle(); + if (recycle && !src.isRecycled()) src.recycle(); + return ret; + } + + /** + * 添加文字水印 + * + * @param src 源图片 + * @param content 水印文本 + * @param textSize 水印字体大小 + * @param color 水印字体颜色 + * @param x 起始坐标x + * @param y 起始坐标y + * @return 带有文字水印的图片 + */ + public static Bitmap addTextWatermark(final Bitmap src, + final String content, + final int textSize, + final int color, + final float x, + final float y) { + return addTextWatermark(src, content, textSize, color, x, y, false); + } + + /** + * 添加文字水印 + * + * @param src 源图片 + * @param content 水印文本 + * @param textSize 水印字体大小 + * @param color 水印字体颜色 + * @param x 起始坐标x + * @param y 起始坐标y + * @param recycle 是否回收 + * @return 带有文字水印的图片 + */ + public static Bitmap addTextWatermark(final Bitmap src, + final String content, + final float textSize, + final int color, + final float x, + final float y, + final boolean recycle) { + if (isEmptyBitmap(src) || content == null) return null; + Bitmap ret = src.copy(src.getConfig(), true); + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + Canvas canvas = new Canvas(ret); + paint.setColor(color); + paint.setTextSize(textSize); + Rect bounds = new Rect(); + paint.getTextBounds(content, 0, content.length(), bounds); + canvas.drawText(content, x, y + textSize, paint); + if (recycle && !src.isRecycled()) src.recycle(); + return ret; + } + + /** + * 添加图片水印 + * + * @param src 源图片 + * @param watermark 图片水印 + * @param x 起始坐标x + * @param y 起始坐标y + * @param alpha 透明度 + * @return 带有图片水印的图片 + */ + public static Bitmap addImageWatermark(final Bitmap src, final Bitmap watermark, final int x, final int y, final int alpha) { + return addImageWatermark(src, watermark, x, y, alpha, false); + } + + /** + * 添加图片水印 + * + * @param src 源图片 + * @param watermark 图片水印 + * @param x 起始坐标x + * @param y 起始坐标y + * @param alpha 透明度 + * @param recycle 是否回收 + * @return 带有图片水印的图片 + */ + public static Bitmap addImageWatermark(final Bitmap src, final Bitmap watermark, final int x, final int y, final int alpha, final boolean recycle) { + if (isEmptyBitmap(src)) return null; + Bitmap ret = src.copy(src.getConfig(), true); + if (!isEmptyBitmap(watermark)) { + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + Canvas canvas = new Canvas(ret); + paint.setAlpha(alpha); + canvas.drawBitmap(watermark, x, y, paint); + } + if (recycle && !src.isRecycled()) src.recycle(); + return ret; + } + + /** + * 转为alpha位图 + * + * @param src 源图片 + * @return alpha位图 + */ + public static Bitmap toAlpha(final Bitmap src) { + return toAlpha(src, false); + } + + /** + * 转为alpha位图 + * + * @param src 源图片 + * @param recycle 是否回收 + * @return alpha位图 + */ + public static Bitmap toAlpha(final Bitmap src, final Boolean recycle) { + if (isEmptyBitmap(src)) return null; + Bitmap ret = src.extractAlpha(); + if (recycle && !src.isRecycled()) src.recycle(); + return ret; + } + + /** + * 转为灰度图片 + * + * @param src 源图片 + * @return 灰度图 + */ + public static Bitmap toGray(final Bitmap src) { + return toGray(src, false); + } + + /** + * 转为灰度图片 + * + * @param src 源图片 + * @param recycle 是否回收 + * @return 灰度图 + */ + public static Bitmap toGray(final Bitmap src, final boolean recycle) { + if (isEmptyBitmap(src)) return null; + Bitmap grayBitmap = Bitmap.createBitmap(src.getWidth(), + src.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(grayBitmap); + Paint paint = new Paint(); + ColorMatrix colorMatrix = new ColorMatrix(); + colorMatrix.setSaturation(0); + ColorMatrixColorFilter colorMatrixColorFilter = new ColorMatrixColorFilter(colorMatrix); + paint.setColorFilter(colorMatrixColorFilter); + canvas.drawBitmap(src, 0, 0, paint); + if (recycle && !src.isRecycled()) src.recycle(); + return grayBitmap; + } + + /** + * 保存图片 + * + * @param src 源图片 + * @param filePath 要保存到的文件路径 + * @param format 格式 + * @return {@code true}: 成功
{@code false}: 失败 + */ + public static boolean save(final Bitmap src, final String filePath, final CompressFormat format) { + return save(src, FileUtils.getFileByPath(filePath), format, false); + } + + /** + * 保存图片 + * + * @param src 源图片 + * @param file 要保存到的文件 + * @param format 格式 + * @return {@code true}: 成功
{@code false}: 失败 + */ + public static boolean save(final Bitmap src, final File file, final CompressFormat format) { + return save(src, file, format, false); + } + + /** + * 保存图片 + * + * @param src 源图片 + * @param filePath 要保存到的文件路径 + * @param format 格式 + * @param recycle 是否回收 + * @return {@code true}: 成功
{@code false}: 失败 + */ + public static boolean save(final Bitmap src, final String filePath, final CompressFormat format, final boolean recycle) { + return save(src, FileUtils.getFileByPath(filePath), format, recycle); + } + + /** + * 保存图片 + * + * @param src 源图片 + * @param file 要保存到的文件 + * @param format 格式 + * @param recycle 是否回收 + * @return {@code true}: 成功
{@code false}: 失败 + */ + public static boolean save(final Bitmap src, final File file, final CompressFormat format, final boolean recycle) { + if (isEmptyBitmap(src) || !FileUtils.createOrExistsFile(file)) return false; + System.out.println(src.getWidth() + ", " + src.getHeight()); + OutputStream os = null; + boolean ret = false; + try { + os = new BufferedOutputStream(new FileOutputStream(file)); + ret = src.compress(format, 100, os); + if (recycle && !src.isRecycled()) src.recycle(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + CloseUtils.closeIO(os); + } + return ret; + } + + /** + * 根据文件名判断文件是否为图片 + * + * @param file  文件 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isImage(final File file) { + return file != null && isImage(file.getPath()); + } + + /** + * 根据文件名判断文件是否为图片 + * + * @param filePath  文件路径 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isImage(final String filePath) { + String path = filePath.toUpperCase(); + return path.endsWith(".PNG") || path.endsWith(".JPG") + || path.endsWith(".JPEG") || path.endsWith(".BMP") + || path.endsWith(".GIF"); + } + + /** + * 获取图片类型 + * + * @param filePath 文件路径 + * @return 图片类型 + */ + public static String getImageType(final String filePath) { + return getImageType(FileUtils.getFileByPath(filePath)); + } + + /** + * 获取图片类型 + * + * @param file 文件 + * @return 图片类型 + */ + public static String getImageType(final File file) { + if (file == null) return null; + InputStream is = null; + try { + is = new FileInputStream(file); + return getImageType(is); + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + CloseUtils.closeIO(is); + } + } + + /** + * 流获取图片类型 + * + * @param is 图片输入流 + * @return 图片类型 + */ + public static String getImageType(final InputStream is) { + if (is == null) return null; + try { + byte[] bytes = new byte[8]; + return is.read(bytes, 0, 8) != -1 ? getImageType(bytes) : null; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * 获取图片类型 + * + * @param bytes bitmap的前8字节 + * @return 图片类型 + */ + public static String getImageType(final byte[] bytes) { + if (isJPEG(bytes)) return "JPEG"; + if (isGIF(bytes)) return "GIF"; + if (isPNG(bytes)) return "PNG"; + if (isBMP(bytes)) return "BMP"; + return null; + } + + private static boolean isJPEG(final byte[] b) { + return b.length >= 2 + && (b[0] == (byte) 0xFF) && (b[1] == (byte) 0xD8); + } + + private static boolean isGIF(final byte[] b) { + return b.length >= 6 + && b[0] == 'G' && b[1] == 'I' + && b[2] == 'F' && b[3] == '8' + && (b[4] == '7' || b[4] == '9') && b[5] == 'a'; + } + + private static boolean isPNG(final byte[] b) { + return b.length >= 8 + && (b[0] == (byte) 137 && b[1] == (byte) 80 + && b[2] == (byte) 78 && b[3] == (byte) 71 + && b[4] == (byte) 13 && b[5] == (byte) 10 + && b[6] == (byte) 26 && b[7] == (byte) 10); + } + + private static boolean isBMP(final byte[] b) { + return b.length >= 2 + && (b[0] == 0x42) && (b[1] == 0x4d); + } + + /** + * 判断bitmap对象是否为空 + * + * @param src 源图片 + * @return {@code true}: 是
{@code false}: 否 + */ + private static boolean isEmptyBitmap(final Bitmap src) { + return src == null || src.getWidth() == 0 || src.getHeight() == 0; + } + + /////////////////////////////////////////////////////////////////////////// + // 下方和压缩有关 + /////////////////////////////////////////////////////////////////////////// + + /** + * 按缩放压缩 + * + * @param src 源图片 + * @param newWidth 新宽度 + * @param newHeight 新高度 + * @return 缩放压缩后的图片 + */ + public static Bitmap compressByScale(final Bitmap src, final int newWidth, final int newHeight) { + return scale(src, newWidth, newHeight, false); + } + + /** + * 按缩放压缩 + * + * @param src 源图片 + * @param newWidth 新宽度 + * @param newHeight 新高度 + * @param recycle 是否回收 + * @return 缩放压缩后的图片 + */ + public static Bitmap compressByScale(final Bitmap src, final int newWidth, final int newHeight, final boolean recycle) { + return scale(src, newWidth, newHeight, recycle); + } + + /** + * 按缩放压缩 + * + * @param src 源图片 + * @param scaleWidth 缩放宽度倍数 + * @param scaleHeight 缩放高度倍数 + * @return 缩放压缩后的图片 + */ + public static Bitmap compressByScale(final Bitmap src, final float scaleWidth, final float scaleHeight) { + return scale(src, scaleWidth, scaleHeight, false); + } + + /** + * 按缩放压缩 + * + * @param src 源图片 + * @param scaleWidth 缩放宽度倍数 + * @param scaleHeight 缩放高度倍数 + * @param recycle 是否回收 + * @return 缩放压缩后的图片 + */ + public static Bitmap compressByScale(final Bitmap src, final float scaleWidth, final float scaleHeight, final boolean recycle) { + return scale(src, scaleWidth, scaleHeight, recycle); + } + + /** + * 按质量压缩 + * + * @param src 源图片 + * @param quality 质量 + * @return 质量压缩后的图片 + */ + public static Bitmap compressByQuality(final Bitmap src, @IntRange(from = 0, to = 100) final int quality) { + return compressByQuality(src, quality, false); + } + + /** + * 按质量压缩 + * + * @param src 源图片 + * @param quality 质量 + * @param recycle 是否回收 + * @return 质量压缩后的图片 + */ + public static Bitmap compressByQuality(final Bitmap src, @IntRange(from = 0, to = 100) final int quality, final boolean recycle) { + if (isEmptyBitmap(src)) return null; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + src.compress(CompressFormat.JPEG, quality, baos); + byte[] bytes = baos.toByteArray(); + if (recycle && !src.isRecycled()) src.recycle(); + return BitmapFactory.decodeByteArray(bytes, 0, bytes.length); + } + + /** + * 按质量压缩 + * + * @param src 源图片 + * @param maxByteSize 允许最大值字节数 + * @return 质量压缩压缩过的图片 + */ + public static Bitmap compressByQuality(final Bitmap src, final long maxByteSize) { + return compressByQuality(src, maxByteSize, false); + } + + /** + * 按质量压缩 + * + * @param src 源图片 + * @param maxByteSize 允许最大值字节数 + * @param recycle 是否回收 + * @return 质量压缩压缩过的图片 + */ + public static Bitmap compressByQuality(final Bitmap src, final long maxByteSize, final boolean recycle) { + if (isEmptyBitmap(src) || maxByteSize <= 0) return null; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int quality = 100; + src.compress(CompressFormat.JPEG, quality, baos); + while (baos.toByteArray().length > maxByteSize && quality > 0) { + baos.reset(); + src.compress(CompressFormat.JPEG, quality -= 5, baos); + } + if (quality < 0) return null; + byte[] bytes = baos.toByteArray(); + if (recycle && !src.isRecycled()) src.recycle(); + return BitmapFactory.decodeByteArray(bytes, 0, bytes.length); + } + + /** + * 按采样大小压缩 + * + * @param src 源图片 + * @param sampleSize 采样率大小 + * @return 按采样率压缩后的图片 + */ + public static Bitmap compressBySampleSize(final Bitmap src, final int sampleSize) { + return compressBySampleSize(src, sampleSize, false); + } + + /** + * 按采样大小压缩 + * + * @param src 源图片 + * @param sampleSize 采样率大小 + * @param recycle 是否回收 + * @return 按采样率压缩后的图片 + */ + public static Bitmap compressBySampleSize(final Bitmap src, final int sampleSize, final boolean recycle) { + if (isEmptyBitmap(src)) return null; + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inSampleSize = sampleSize; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + src.compress(CompressFormat.JPEG, 100, baos); + byte[] bytes = baos.toByteArray(); + if (recycle && !src.isRecycled()) src.recycle(); + return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); + } + + private static boolean isSpace(final String s) { + if (s == null) return true; + for (int i = 0, len = s.length(); i < len; ++i) { + if (!Character.isWhitespace(s.charAt(i))) { + return false; + } + } + return true; + } +} diff --git a/app/src/main/java/com/fenghoo/seven/utils/Utils.java b/app/src/main/java/com/fenghoo/seven/utils/Utils.java new file mode 100644 index 0000000..b834edc --- /dev/null +++ b/app/src/main/java/com/fenghoo/seven/utils/Utils.java @@ -0,0 +1,192 @@ +package com.fenghoo.seven.utils; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Bundle; +import android.telephony.TelephonyManager; +import android.util.Base64; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.View; +import android.view.WindowManager; + +import java.io.ByteArrayInputStream; + +import androidx.annotation.NonNull; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 16/12/08
+ *     desc  : Utils初始化相关
+ * 
+ */ +public final class Utils { + + @SuppressLint("StaticFieldLeak") + private static Context context; + + private Utils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * 初始化工具类 + * + * @param context 上下文 + */ + public static void init(@NonNull final Context context) { + Utils.context = context.getApplicationContext(); + } + + /** + * 获取ApplicationContext + * + * @return ApplicationContext + */ + public static Context getContext() { + if (context != null) return context; + throw new NullPointerException("u should init first"); + } + public static int dip2px(Context context, float dpValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale); + } + + public static int px2dip(Context context, float pxValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale); + } + + public static int getVisiblePercent(View pView) { + if (pView != null && pView.isShown()) { + DisplayMetrics displayMetrics = pView.getContext().getResources().getDisplayMetrics(); + int displayWidth = displayMetrics.widthPixels; + Rect rect = new Rect(); + pView.getGlobalVisibleRect(rect); + if ((rect.top > 0) && (rect.left < displayWidth)) { + double areaVisible = rect.width() * rect.height(); + double areaTotal = pView.getWidth() * pView.getHeight(); + return (int) ((areaVisible / areaTotal) * 100); + } else { + return -1; + } + } + return -1; + } + + //is wifi connected + public static boolean isWifiConnected(Context context) { + if (context.checkCallingOrSelfPermission(Manifest.permission.ACCESS_WIFI_STATE) + != PackageManager.PERMISSION_GRANTED) { + return false; + } + ConnectivityManager connectivityManager = (ConnectivityManager) + context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo info = connectivityManager.getActiveNetworkInfo(); + if (info != null && info.isConnected() && info.getType() == ConnectivityManager.TYPE_WIFI) { + return true; + } + return false; + } + + + /** + * 获取对应应用的版本号 + * + * @param context + * @return + */ + public static String getAppVersion(Context context) { + String version = "1.0.0"; //默认1.0.0版本 + PackageManager manager = context.getPackageManager(); + try { + PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0); + version = info.versionName; + } catch (Exception e) { + } + + return version; + } + + + public static DisplayMetrics getDisplayMetrics(Context context) { + DisplayMetrics displayMetrics = new DisplayMetrics(); + WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + if (windowManager == null) { + return displayMetrics; + } + windowManager.getDefaultDisplay().getMetrics(displayMetrics); + return displayMetrics; + } + + public static BitmapDrawable decodeImage(String base64drawable) { + byte[] rawImageData = Base64.decode(base64drawable, 0); + return new BitmapDrawable(null, new ByteArrayInputStream(rawImageData)); + } + + public static boolean isPad(Context context) { + + //如果能打电话那可能是平板或手机,再根据配置判断 + if (canTelephone(context)) { + //能打电话可能是手机也可能是平板 + return (context.getResources().getConfiguration(). + screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) + >= Configuration.SCREENLAYOUT_SIZE_LARGE; + } else { + return true; //不能打电话一定是平板 + } + } + + private static boolean canTelephone(Context context) { + TelephonyManager telephony = (TelephonyManager) + context.getSystemService(Context.TELEPHONY_SERVICE); + return (telephony.getPhoneType() == TelephonyManager.PHONE_TYPE_NONE) ? false : true; + } + + public static boolean containString(String source, String destation) { + + if (source.equals("") || destation.equals("")) { + return false; + } + + if (source.contains(destation)) { + return true; + } + return false; + } + + /** + * 获取view的屏幕属性 + * + * @return + */ + public static final String VIEW_INFO_EXTRA = "view_into_extra"; + public static final String PROPNAME_SCREENLOCATION_LEFT = "propname_sreenlocation_left"; + public static final String PROPNAME_SCREENLOCATION_TOP = "propname_sreenlocation_top"; + public static final String PROPNAME_WIDTH = "propname_width"; + public static final String PROPNAME_HEIGHT = "propname_height"; + + public static Bundle getViewProperty(View view) { + Bundle bundle = new Bundle(); + int[] screenLocation = new int[2]; + view.getLocationOnScreen(screenLocation); //获取view在整个屏幕中的位置 + bundle.putInt(PROPNAME_SCREENLOCATION_LEFT, screenLocation[0]); + bundle.putInt(PROPNAME_SCREENLOCATION_TOP, screenLocation[1]); + bundle.putInt(PROPNAME_WIDTH, view.getWidth()); + bundle.putInt(PROPNAME_HEIGHT, view.getHeight()); + + Log.e("Utils", "Left: " + screenLocation[0] + " Top: " + screenLocation[1] + + " Width: " + view.getWidth() + " Height: " + view.getHeight()); + return bundle; + } +} diff --git a/app/src/main/res/layout/activity_add_customer.xml b/app/src/main/res/layout/activity_add_customer.xml index 2bd368f..bdc3deb 100644 --- a/app/src/main/res/layout/activity_add_customer.xml +++ b/app/src/main/res/layout/activity_add_customer.xml @@ -5,7 +5,13 @@ android:layout_height="match_parent" xmlns:omi="http://schemas.android.com/apk/res-auto"> + +