提交 6e93e567 编写于 作者: 门心叼龙's avatar 门心叼龙

module init commit

上级 57304785
...@@ -8,7 +8,12 @@ ...@@ -8,7 +8,12 @@
<option name="modules"> <option name="modules">
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" /> <option value="$PROJECT_DIR$/lib_common" />
<option value="$PROJECT_DIR$/module_app" />
<option value="$PROJECT_DIR$/module_find" />
<option value="$PROJECT_DIR$/module_main" />
<option value="$PROJECT_DIR$/module_me" />
<option value="$PROJECT_DIR$/module_trip" />
</set> </set>
</option> </option>
<option name="resolveModulePerSourceSet" value="false" /> <option name="resolveModulePerSourceSet" value="false" />
......
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
...@@ -5,23 +5,27 @@ buildscript { ...@@ -5,23 +5,27 @@ buildscript {
repositories { repositories {
google() google()
jcenter() jcenter()
mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.2.1' classpath 'com.android.tools.build:gradle:3.2.1'
//classpath 'com.jakewharton:butterknife-gradle-plugin:9.0.0-rc3'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
} }
repositories {
}
} }
allprojects { allprojects {
repositories { repositories {
google() google()
jcenter() jcenter()
mavenCentral()
maven { url 'https://jitpack.io' }
} }
} }
task clean(type: Delete) { task clean(type: Delete) {
delete rootProject.buildDir delete rootProject.buildDir
} }
...@@ -11,5 +11,6 @@ org.gradle.jvmargs=-Xmx1536m ...@@ -11,5 +11,6 @@ org.gradle.jvmargs=-Xmx1536m
# This option should only be used with decoupled projects. More details, visit # This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true # org.gradle.parallel=true
isModule=true
#android.enableAapt2=false
apply plugin: 'com.android.library'
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 14
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.android.support:design:28.0.0'
implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
implementation 'com.github.tbruyelle:rxpermissions:0.10.2'
implementation 'com.github.lovetuzitong:MultiImageSelector:1.2'
}
package com.fly.tour.common;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.fly.tour.common.test", appContext.getPackageName());
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fly.tour.common"/>
package com.fly.tour.common;
import android.app.Application;
/**
* Description: <初始化应用程序><br>
* Author: gxl<br>
* Date: 2018/6/6<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class BaseApplication extends Application {
private static BaseApplication mApplication;
@Override
public void onCreate() {
super.onCreate();
mApplication = this;
}
public static BaseApplication getInstance(){
return mApplication;
}
}
package com.fly.tour.common.adapter;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by gxl on 2017/12/25.
*/
public abstract class BaseHeaderRecycleAdapter<E, VH extends RecyclerView.ViewHolder> extends BaseRecycelerViewAdapter<E, RecyclerView.ViewHolder> {
public static final int TYPE_HEADER = 0;
public static final int TYPE_NORMAL = 1;
private View mHeaderView;
public BaseHeaderRecycleAdapter(Context context) {
super(context);
}
@Override
public int getItemCount() {
return mHeaderView == null ? mList.size() : mList.size() + 1;
}
@Override
public int getItemViewType(int position) {
if (mHeaderView == null) {
return TYPE_NORMAL;
}
if (position == 0) {
return TYPE_HEADER;
}
return TYPE_NORMAL;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (mHeaderView != null && viewType == TYPE_HEADER) {
return new HeaderViewHolder(mHeaderView) {
};
}
return super.onCreateViewHolder(parent, viewType);
};
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (getItemViewType(position) == TYPE_HEADER) {
return;
}
super.onBindViewHolder(holder, getRealPosition(holder));
}
public int getRealPosition(RecyclerView.ViewHolder holder) {
int position = holder.getLayoutPosition();
return mHeaderView == null ? position : position - 1;
}
public View getHeaderView() {
return mHeaderView;
}
public void setHeaderView(View headerView) {
mHeaderView = headerView;
}
class HeaderViewHolder extends RecyclerView.ViewHolder{
public HeaderViewHolder(View itemView) {
super(itemView);
}
}
}
package com.fly.tour.common.adapter;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import java.util.List;
/**
* Description: <BaseListViewAdapter><br>
* Author: gxl<br>
* Date: 2018/6/11<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public abstract class BaseListViewAdapter<T> extends BaseAdapter {
protected Context mContext;
protected List<T> list;
public BaseListViewAdapter(Context context, List<T> mDatas) {
this.mContext = context;
this.list = mDatas;
}
@Override
public int getCount() {
if (list != null) {
return list.size();
}
return 0;
}
@Override
public Object getItem(int position) {
if (list != null && list.size() > 0) {
return list.get(position);
}
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return inflateView(position, convertView, parent);
}
public abstract View inflateView(int position, View convertView, ViewGroup parent);
}
package com.fly.tour.common.adapter;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
/**
* Description: <BaseRecycelerViewAdapter><br>
* Author: gxl<br>
* Date: 2018/6/11<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public abstract class BaseRecycelerViewAdapter<E, VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH> {
protected Context mContext;
protected List<E> mList;
protected OnItemClickListener mOnItemClickListener;
protected OnLongItemClickListener mOnLongItemClickListener;
public abstract int onBindLayout();
public abstract VH onCreateViewHolder(View view);
public abstract void convert(VH holder, int position);
public BaseRecycelerViewAdapter(Context context) {
this.mContext = context;
this.mList = new ArrayList<E>();
}
@Override
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
int layout = onBindLayout();
View view = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false);
return onCreateViewHolder(view);
}
@Override
public void onBindViewHolder(VH holder, final int position) {
if (mOnItemClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mOnItemClickListener.onItemClick(position);
}
});
}
if (mOnLongItemClickListener != null) {
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
return mOnLongItemClickListener.onLongItemClick(position);
}
});
}
convert(holder, position);
}
public E remove(int position) {
E remove = mList.remove(position);
notifyDataSetChanged();
return remove;
}
public void clear() {
mList.clear();
notifyDataSetChanged();
}
public void addAll(List<E> list) {
mList.addAll(list);
notifyDataSetChanged();
}
public List<E> getList() {
return mList;
}
public E get(int position) {
return mList.get(position);
}
@Override
public int getItemCount() {
return mList.size();
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.mOnItemClickListener = listener;
}
public void setOnLongItemClickListener(OnLongItemClickListener listener) {
this.mOnLongItemClickListener = listener;
}
public interface OnItemClickListener {
void onItemClick(int position);
}
public interface OnLongItemClickListener {
boolean onLongItemClick(int position);
}
}
package com.fly.tour.common.adapter;
/**
* Description: <><br>
* Author: gxl<br>
* Date: 2018/6/11<br>
* Version: V1.0.0<br>
* Update: <br>
*/
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
/**
* Description: <BaseViewPagerAdapter></br>
* Author: gxl</br>
* Date: 2018/3/9</br>
* Version: V1.0.0</br>
* Update: </br>
*/
public class BaseViewPagerAdapter<T> extends PagerAdapter {
protected Context mContext;
protected List<T> list;
public BaseViewPagerAdapter(Context context, List<T> list) {
mContext = context;
this.list = list;
}
@Override
public int getCount() {
return list == null ? 0 : list.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void destroyItem(ViewGroup view, int position, Object object) {
view.removeView((View) object);
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
/*--------------------------------------------------
* Copyright (C) 2015 The Android YeswaySDK Project
* http://www.yesway.cn/
* 创建时间:2015/12/21
* 内容说明:Activity操作类
*
* 编号 日期 担当者 内容
* -------------------------------------------------
*
*
*--------------------------------------------------*/
package com.fly.tour.common.base;
import android.app.Activity;
import java.util.ArrayList;
import java.util.List;
/**
* Description: <Activity管理器><br>
* Author: gxl<br>
* Date: 2018/6/6<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class ActivityCollectManager {
private static List<Activity> mActivityList = new ArrayList<Activity>();
public static void addActivity(Activity activity) {
mActivityList.add(activity);
}
public static void removeActivity(Activity activity) {
mActivityList.remove(activity);
}
public static void finishAllActivity() {
for (Activity activity : mActivityList) {
if (activity.isFinishing() == false) {
activity.finish();
}
}
}
}
package com.fly.tour.common.base;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewStub;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;
import com.fly.tour.common.R;
/**
* Description: <公共的activity基类><br>
* Author: gxl<br>
* Date: 2018/6/6<br>
* Version: V1.0.0<br>
* Update: <br>
*
*/
public abstract class BaseActivity extends AppCompatActivity {
public static final String TAG = "YESWAY";
public BaseActivity mActivity;
private TextView mTxtTitle;
private Toolbar mToolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityCollectManager.addActivity(this);
mActivity = this;
initView(savedInstanceState);
initData();
}
@Override
public void setContentView(int layoutResID) {
//加载跟布局
super.setContentView(R.layout.base_activity);
mToolbar = findView(R.id.toolbar);
setSupportActionBar(mToolbar);
if (mTxtTitle != null && getSupportActionBar() != null){
getSupportActionBar().setDisplayShowTitleEnabled(false);
}
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
// 加载子类要显示的布局
ViewStub content_viewStub = (ViewStub) findViewById(R.id.content_viewStub);
content_viewStub.setLayoutResource(layoutResID);
content_viewStub.inflate();
mTxtTitle = findView(R.id.txt_toolbar_title);
}
@Override
protected void onDestroy() {
ActivityCollectManager.removeActivity(this);
super.onDestroy();
}
public abstract void initView(Bundle savedInstanceState);
public abstract void initData();
public <M extends View> M findView(int id) {
return (M) findViewById(id);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (null != this.getCurrentFocus()) {
InputMethodManager mInputMethodManager =
(InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
return mInputMethodManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(),
0);
}
return super.onTouchEvent(event);
}
public void closeAllActivity() {
ActivityCollectManager.finishAllActivity();
}
public void openActivity(Class<?> targetActivityClass, Bundle bundle) {
Intent intent = new Intent(this, targetActivityClass);
if (bundle != null) {
intent.putExtras(bundle);
}
startActivity(intent);
}
public void showLoading() {
}
public void hideLoading() {
}
public void showErrNetWork() {
}
@Override
protected void onTitleChanged(CharSequence title, int color) {
super.onTitleChanged(title, color);
if(mTxtTitle != null){
mTxtTitle.setText(title);
}
}
}
package com.fly.tour.common.base;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import butterknife.ButterKnife;
/**
* Description: <公共的Fragment基类><br>
* Author: gxl<br>
* Date: 2018/6/6<br>
* Version: V1.0.0<br>
* Update: <br>
*
*/
public abstract class BaseFragment extends Fragment {
public static final String TAG = "YESWAY";
protected Activity mContext;
public View mView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getActivity();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mView = initView(inflater,container);
ButterKnife.bind(mView);
return mView;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initData(savedInstanceState);
}
@Override
public void onDestroy() {
super.onDestroy();
}
public <M extends View> M findView(View view, int id) {
return (M) view.findViewById(id);
}
public abstract View initView(LayoutInflater inflater,ViewGroup container);
public abstract void initData(Bundle savedInstanceState);
@Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
if (getView() != null) {
getView().setVisibility(menuVisible ? View.VISIBLE : View.GONE);
}
}
}
package com.fly.tour.common.base;
import android.os.Bundle;
/**
* Description: <BaseMvpActivity><br>
* Author: gxl<br>
* Date: 2018/6/11<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public abstract class BaseMvpActivity<V, T extends BasePresenter<V>> extends BaseActivity {
public T mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
mPresenter = initPresenter();
if (mPresenter != null) {
mPresenter.attach((V) this);
}
super.onCreate(savedInstanceState);
}
@Override
protected void onDestroy() {
if (mPresenter != null) {
mPresenter.dettach();
}
super.onDestroy();
}
public abstract T initPresenter();
}
package com.fly.tour.common.base;
import android.os.Bundle;
/**
* Description: <><br>
* Author: gxl<br>
* Date: 2018/6/11<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public abstract class BaseMvpFragment<V, T extends BasePresenter<V>> extends BaseFragment {
public T mPresenter;
@Override
public void onCreate(Bundle savedInstanceState) {
mPresenter = initPresenter();
if (mPresenter != null) {
mPresenter.attach((V) this);
}
super.onCreate(savedInstanceState);
}
@Override
public void onDestroy() {
if (mPresenter != null) {
mPresenter.dettach();
}
super.onDestroy();
}
public abstract T initPresenter();
}
package com.fly.tour.common.base;
public abstract class BasePresenter<V> {
public V mView;
public void attach(V mView) {
this.mView = mView;
}
public void dettach() {
mView = null;
}
}
package com.fly.tour.common.base;
public interface IBaseView {
void showLoading();
void hideLoading();
void showErrNetWork();
}
package com.fly.tour.common.util;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.media.ExifInterface;
import android.net.Uri;
import android.util.Log;
import android.view.View;
import android.view.View.MeasureSpec;
import android.widget.ScrollView;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
/**
* Description: <BitmapUtil><br>
* <ul>
* <h1>功能列表:</h1>
* <li>1.将scrollView转化为bitmap</li>
* <li>2.将View转化为bitmap</li>
* <li>3.将文本和view合拼生成一个bitmap</li>
* <li>4.将一个bitmap转化为一个字节数组</li>
* <li>5.将一个字节数组转化为一个bitmap</li>
* <li>6.等比压缩Bitmap到720P内</li>
* <li>7.图片压缩到 100 * 100 像素</li>
* <li>8.图片压缩到指定的size</li>
* <li>9.bitmap缩放到指定的宽和高</li>
* <li>10.网络url获取Btimep,非异步操作,会有延迟</li>
* <li>11.读取图片的旋转的角度</li>
* <li>12.将图片按照某个角度进行旋转</li>
* </ul>
* Author: gxl<br>
* Date: 2018/6/11<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class BitmapUtil {
/**
* 截取竖scrollview的屏幕
*
* 因为部分手机屏幕分辨率大,导致生成的bitmap会出现OOM异常,所以将view的bitmap设置为720p
*
* @param scrollView
* @return
*/
public static Bitmap convertViewToBitmap(ScrollView scrollView) {
int h = 0;
// 获取scrollview实际高度
for (int i = 0; i < scrollView.getChildCount(); i++) {
h += scrollView.getChildAt(i).getHeight();
scrollView.getChildAt(i).setBackgroundColor(Color.WHITE); // 透明色背景会出现黑色,设置为白色,应该考虑父级背景色
}
Bitmap bitmap = Bitmap.createBitmap(scrollView.getWidth(), h, Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
scrollView.draw(canvas);
return scaled720Bitmap(bitmap);
}
/**
* 将View生成bitmap
*
* 因为部分手机屏幕分辨率大,导致生成的bitmap会出现OOM异常,所以将view的bitmap设置为720p
*
* @param view 要生成bitmap的View
* @return
*/
public static Bitmap convertViewToBitmap(View view) {
if (view == null) return null;
view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
view.buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(scaled720Bitmap(view.getDrawingCache()));
view.destroyDrawingCache();
return bitmap;
}
/**
* 合并Bitmap,该方法主要用于微信分享,添加标题栏的合并
*
* @return
*/
public static Bitmap combineBitmap_Title(Context context, String titleStr, View view) {
if (context == null || view == null) return null;
Bitmap bitmap = view instanceof ScrollView
? convertViewToBitmap((ScrollView) view)
: convertViewToBitmap(view);
Paint textPaint = new Paint();
textPaint.setAntiAlias(true);
textPaint.setColor(Color.WHITE);
textPaint.setTextSize(DisplayUtil.sp2px(16));
// 文本的宽高
Paint.FontMetrics fm = textPaint.getFontMetrics();
float textWidth = textPaint.measureText(titleStr);
float textHeight = (float) Math.ceil(fm.descent - fm.ascent);
// 标题栏的高度
int titleHeight = DisplayUtil.dip2px(40);
// 先生成标题栏的bitmap,因为根据当前设备制作的标题栏要进行720P的压缩
Bitmap titleBitmap = Bitmap.createBitmap(bitmap.getWidth(), titleHeight, Bitmap.Config.RGB_565);
Canvas titleCanvas = new Canvas(titleBitmap);
// 绘制标题栏背景色
Paint titlePaint = new Paint();
titlePaint.setAntiAlias(true);
// ******** 5.0标题颜色待确定 ********************
// titlePaint.setColor(context.getResources().getColor(R.color.title_bg));
titlePaint.setStrokeWidth(titleHeight);
titleCanvas.drawLine(0, titleHeight / 2, bitmap.getWidth(), titleHeight / 2, titlePaint);
// 绘制标题文字
titleCanvas.drawText(titleStr, bitmap.getWidth() / 2 - textWidth / 2,
titleHeight / 2 + textHeight / 3, textPaint);
//??? titleCanvas.save(Canvas.ALL_SAVE_FLAG);
titleCanvas.restore();
titleBitmap = Bitmap.createScaledBitmap(titleBitmap, 720,
(int) ((720f / titleBitmap.getWidth()) * titleBitmap.getHeight()), true);
// 合成两个bitmap
Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight() + titleBitmap.getHeight(), Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(newBitmap);
canvas.drawBitmap(titleBitmap, 0, 0, null);
canvas.drawBitmap(bitmap, 0, titleBitmap.getHeight(), null);
//????canvas.save(Canvas.ALL_SAVE_FLAG);
canvas.restore();
bitmap.recycle();
titleBitmap.recycle();
return newBitmap;
}
public static byte[] bmpToByteArray(Bitmap bm) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
return baos.toByteArray();
}
public static Bitmap bytesToBimap(byte[] b) {
if (b.length == 0) return null;
return BitmapFactory.decodeByteArray(b, 0, b.length);
}
public static byte[] bmpToByteArray(final Bitmap bmp, final boolean needRecycle) {
if (bmp == null) return null;
ByteArrayOutputStream output = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, output);
byte[] result = output.toByteArray();
try {
output.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 等比压缩Bitmap到720P内
*
* @param bitmap
* @return
*/
private static Bitmap scaled720Bitmap(Bitmap bitmap) {
if (bitmap == null) return null;
int width, height;
if (bitmap.getWidth() > bitmap.getHeight()) {
if (bitmap.getHeight() <= 720) return bitmap;
height = 720;
width = (int) ((720f / bitmap.getHeight()) * bitmap.getWidth());
} else {
if (bitmap.getWidth() <= 720) return bitmap;
width = 720;
height = (int) ((720f / bitmap.getWidth()) * bitmap.getHeight());
}
return Bitmap.createScaledBitmap(bitmap, width, height, true);
}
/**
* 图片压缩到 100 * 100 像素
*
* @param bitmap
* @return
*/
public static Bitmap scaleTo100Bitmap(Bitmap bitmap) {
return scaleTo(bitmap, 100, 100);
}
public static byte[] compressImage(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
int options = 100;
while (baos.toByteArray().length / 1024 > 100) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
baos.reset();// 重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中
options -= 10;// 每次都减少10
}
// ByteArrayInputStream isBm = new
// ByteArrayInputStream(baos.toByteArray());//
// 把压缩后的数据baos存放到ByteArrayInputStream中
// Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//
// 把ByteArrayInputStream数据生成图片
return baos.toByteArray();
}
public static Bitmap compressImage(Bitmap image, int targetSize) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
Log.d("bitmapUtil", "要压缩的bitmap大小 : " + baos.toByteArray().length / 1024);
int options = 100;
while (baos.toByteArray().length / 1024 > targetSize) { // 循环判断如果压缩后图片是否大于指定的kb,大于继续压缩
baos.reset();// 重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中
options -= 10;// 每次都减少10
}
Log.d("bitmapUtil", "压缩后的bitmap大小 : " + baos.toByteArray().length / 1024);
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//
// 把压缩后的数据baos存放到ByteArrayInputStream中
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//
// 把ByteArrayInputStream数据生成图片
return bitmap;
}
public static Bitmap scaleTo(Bitmap bitmap, int width, int height) {
if (bitmap == null) return null;
int w, h;
if (bitmap.getWidth() > bitmap.getHeight()) {
if (bitmap.getHeight() <= height) return bitmap;
h = height;
w = (int) ((100f / bitmap.getHeight()) * bitmap.getWidth());
} else {
if (bitmap.getWidth() <= width) return bitmap;
w = width;
h = (int) ((100f / bitmap.getWidth()) * bitmap.getHeight());
}
return Bitmap.createScaledBitmap(bitmap, w, h, true);
}
/**
* 网络url获取Btimep,非异步操作,会有延迟
*
* @param strUrl
* @return
*/
public static Bitmap getBitMap(String strUrl) {
Bitmap bitmap = null;
InputStream is = null;
try {
URL url = new URL(strUrl);
URLConnection conn = url.openConnection();
is = conn.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
bitmap = BitmapFactory.decodeStream(is);
return bitmap;
}
/**
* 将bitmap压缩至目标大小
*
* @param maxImageSize
* @param filter
* @return
*/
public static Bitmap scaleDown(Uri imageUri, float maxImageSize, boolean filter) {
Bitmap result = null;
try {
File file = new File(new URI(imageUri.toString()));
Bitmap realImage = BitmapFactory.decodeFile(imageUri.getPath());
long size = file.length();
float ratio = size / maxImageSize;
int width = Math.round((float) realImage.getWidth() / ratio);
int height = Math.round((float) realImage.getHeight() / ratio);
result = Bitmap.createScaledBitmap(realImage, width, height, filter);
} catch (URISyntaxException e) {
e.printStackTrace();
}
return result;
}
public static Bitmap decodeSampledBitmapFromResource(Uri imageUri, int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageUri.getPath(), options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(imageUri.getPath(), options);
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth,
int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and
// width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? widthRatio : heightRatio;
// final int halfHeight = height / 2;
// final int halfWidth = width / 2;
//
// while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth)
// {
// inSampleSize *= 2;
// }
}
return inSampleSize;
}
/**
* 读取图片的旋转的角度
*
* @param path 图片绝对路径
* @return 图片的旋转角度
*/
public static int getBitmapDegree(String path) {
int degree = 0;
try {
// 从指定路径下读取图片,并获取其EXIF信息
ExifInterface exifInterface = new ExifInterface(path);
// 获取图片的旋转信息
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
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 bm 需要旋转的图片
* @param degree 旋转角度
* @return 旋转后的图片
*/
public static Bitmap rotateBitmapByDegree(Bitmap bm, int degree) {
Bitmap returnBm = null;
// 根据旋转角度,生成旋转矩阵
Matrix matrix = new Matrix();
matrix.postRotate(degree);
try {
// 将原始图片按照旋转矩阵进行旋转,并得到新的图片
returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
} catch (OutOfMemoryError e) {}
if (returnBm == null) {
returnBm = bm;
}
if (bm != returnBm) {
bm.recycle();
}
return returnBm;
}
/**
* 获取压缩后的图片
*
* @return
*/
public static Bitmap decodeBitmapFromFile(String path, int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
}
\ No newline at end of file
package com.fly.tour.common.util;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Looper;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Properties;
import java.util.TreeSet;
/**
* 线程未捕获异常控制器是用来处理未捕获异常的。
* <p>
* UncaughtException处理类,当程序发生Uncaught异常的时候,由该类来接管程序,并记录发送错误报告.
*/
public class CrashHandler implements Thread.UncaughtExceptionHandler {
/**
* Debug Log Tag
*/
public static final String TAG = "YESWAY-CrashHandler";
/**
* 是否开启日志输出, 在Debug状态下开启, 在Release状态下关闭以提升程序性能
*/
public static final boolean DEBUG = true;
/**
* CrashHandler实例
*/
private static CrashHandler mCrashHandler;
/**
* 程序的Context对象
*/
private Context mContext;
/**
* 系统默认的UncaughtException处理类
*/
private Thread.UncaughtExceptionHandler mDefaultHandler;
/**
* 使用Properties来保存设备的信息和错误堆栈信息
*/
private Properties mDeviceCrashInfo = new Properties();
/**
* 版本
*/
private static final String VERSION_NAME = "versionName";
/**
* 版本号
*/
private static final String VERSION_CODE = "versionCode";
/**
* 堆栈名
*/
private static final String STACK_TRACE = "STACK_TRACE";
/**
* 错误报告文件的扩展名
*/
private static final String CRASH_REPORTER_EXTENSION = ".txt";
/**
* 保证只有一个CrashHandler实例
*/
private CrashHandler() {
}
/**
* 获取CrashHandler实例 ,单例模式
*/
public static CrashHandler getInstance() {
if (mCrashHandler == null) {
mCrashHandler = new CrashHandler();
}
return mCrashHandler;
}
/**
* 初始化,注册Context对象, 获取系统默认的UncaughtException处理器, 设置该CrashHandler为程序的默认处理器
*
* @param ctx
*/
public void init(Context ctx) {
mContext = ctx;
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
* 当UncaughtException发生时会转入该函数来处理
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
// MobclickAgent.reportError(context, ex);
// 退出程序
ToastUtil.showToast("发生异常,已重启应用");
// EnvironmentUtil.openApp(mContext, SplashActivity.class.getName());
// Intent intent = new Intent(Intent.ACTION_MAIN);
// intent.addCategory(Intent.CATEGORY_LAUNCHER);
// ComponentName cn = new ComponentName(mContext.getPackageName(), className);
// intent.setComponent(cn);
// intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
// mContext.startActivity(intent);
String packageName = mContext.getPackageName();
// Log.v("TEST","packageName:"+packageName);
Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(packageName);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
mContext.startActivity(intent);
android.os.Process.killProcess(android.os.Process.myPid());
}
}
private static void openApp(Context context, String className) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
ComponentName cn = new ComponentName(context.getPackageName(), className);
intent.setComponent(cn);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
}
/**
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. 开发者可以根据自己的情况来自定义异常处理逻辑
*
* @param ex
* @return true:如果处理了该异常信息;否则返回false
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return true;
}
// final String msg = ex.getLocalizedMessage();
// 使用Toast来显示异常信息
new Thread() {
@Override
public void run() {
// Toast 显示需要出现在一个线程的消息队列中
Looper.prepare();
ToastUtil.showToast("程序异常,请重启应用");
Looper.loop();
// 程序出现异常,下次程序进入默认值更改为我的主页
// SaveSharedPreference.setSharedPreferenceInt(mContext,
// "lastSelect", R.id.rb_index_page);
}
}.start();
// 收集设备信息
collectCrashDeviceInfo(mContext);
// 保存错误报告文件
// saveCrashInfoToFile(ex);
// 发送错误报告到服务器
// sendCrashReportsToServer(mContext);
return true;
}
/**
* 收集程序崩溃的设备信息
*
* @param ctx
*/
public void collectCrashDeviceInfo(Context ctx) {
try {
PackageManager pm = ctx.getPackageManager();
PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
if (pi != null) {
mDeviceCrashInfo.put(VERSION_NAME, pi.versionName == null ? "not set" : pi.versionName);
mDeviceCrashInfo.put(VERSION_CODE, pi.versionCode);
}
} catch (Exception e) {
Log.e(TAG, "Error while collect package info" + e);
}
// 使用反射来收集设备信息.在Build类中包含各种设备信息,
Field[] fields = Build.class.getDeclaredFields();
for (Field field : fields) {
try {
// setAccessible(boolean flag)
// 将此对象的 accessible 标志设置为指示的布尔值。
// 通过设置Accessible属性为true,才能对私有变量进行访问,不然会得到一个IllegalAccessException的异常
field.setAccessible(true);
mDeviceCrashInfo.put(field.getName(), field.get(null));
if (DEBUG) {
Log.d(TAG, field.getName() + " : " + field.get(null));
}
} catch (Exception e) {
Log.e(TAG, "Error while collect crash info" + e);
}
}
}
/**
* 保存错误信息到文件中
*
* @param ex
* @return
*/
private String saveCrashInfoToFile(Throwable ex) {
Writer info = new StringWriter();
PrintWriter printWriter = new PrintWriter(info);
// printStackTrace(PrintWriter s)
// 将此 throwable 及其追踪输出到指定的 PrintWriter
ex.printStackTrace(printWriter);
// getCause() 返回此 throwable 的 cause;如果 cause 不存在或未知,则返回 null。
Throwable cause = ex.getCause();
while (cause != null) {
cause.printStackTrace(printWriter);
cause = cause.getCause();
}
// toString() 以字符串的形式返回该缓冲区的当前值。
String result = info.toString();
printWriter.close();
mDeviceCrashInfo.put(STACK_TRACE, result);
try {
String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
String fileName = "crash-" + timestamp + CRASH_REPORTER_EXTENSION;
// 保存文件
File directory = new File(EnvironmentUtil.Storage.getExternalCacheDir(mContext), "logs");
if (!directory.exists()) {
directory.mkdirs();
}
File file = new File(directory, fileName);
FileOutputStream trace = new FileOutputStream(file);
Log.e(TAG, new String(result.getBytes()));
// 写入
trace.write(result.getBytes());
trace.flush();
trace.close();
return fileName;
} catch (Exception e) {
Log.e(TAG, e.toString());
}
return null;
}
/**
* 把错误报告发送给服务器,包含新产生的和以前没发送的.
*
* @param ctx
*/
private void sendCrashReportsToServer(Context ctx) {
String[] crFiles = getCrashReportFiles(ctx);
if (crFiles != null && crFiles.length > 0) {
TreeSet<String> sortedFiles = new TreeSet<String>();
sortedFiles.addAll(Arrays.asList(crFiles));
for (String fileName : sortedFiles) {
File cr = new File(ctx.getFilesDir(), fileName);
postReport(cr);
cr.delete();// 删除已发送的报告
}
}
}
/**
* 获取错误报告文件名
*
* @param ctx
* @return
*/
private String[] getCrashReportFiles(Context ctx) {
File filesDir = ctx.getFilesDir();
// 实现FilenameFilter接口的类实例可用于过滤器文件名
FilenameFilter filter = new FilenameFilter() {
// accept(File dir, String name)
// 测试指定文件是否应该包含在某一文件列表中。
public boolean accept(File dir, String name) {
return name.endsWith(CRASH_REPORTER_EXTENSION);
}
};
// list(FilenameFilter filter)
// 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录
return filesDir.list(filter);
}
private void postReport(File file) {
// 使用HTTP Post 发送错误报告到服务器
// 这里不再详述,开发者可以根据OPhoneSDN上的其他网络操作
}
/**
* 在程序启动时候, 可以调用该函数来发送以前没有发送的报告
*/
public void sendPreviousReportsToServer() {
sendCrashReportsToServer(mContext);
}
}
package com.fly.tour.common.util;
import android.text.TextUtils;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* Description: <DateUtil><br>
* Author: gxl<br>
* Date: 2018/6/11<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class DateUtil {
public enum FormatType {
yyyy, yyyyMM, yyyyMMdd, yyyyMMddHHmm, yyyyMMddHHmmss, MMdd, HHmm
}
/**
* 格式化时间字符串
*/
public static String formatDate(String time, String formatStr) {
Date setdate = parseTime(time);
SimpleDateFormat sdf = new SimpleDateFormat(formatStr);
return sdf.format(setdate);
}
public static String formatDate(String time, FormatType type) {
if (TextUtils.isEmpty(time)) {
return "";
}
Date date = parseTime(time);
return formatDate(date, type);
}
public static String formatDate(Date time, FormatType type) {
if (time == null) {
return "";
}
SimpleDateFormat sdf = getSimpleDateFormat(type);
return sdf.format(time);
}
private static SimpleDateFormat getSimpleDateFormat(FormatType type) {
SimpleDateFormat sdf;
switch (type) {
case yyyy:
sdf = new SimpleDateFormat("yyyy");
break;
case yyyyMM:
sdf = new SimpleDateFormat("yyyy-MM");
break;
case yyyyMMdd:
sdf = new SimpleDateFormat("yyyy-MM-dd");
break;
case yyyyMMddHHmm:
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
break;
case yyyyMMddHHmmss:
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
break;
case MMdd:
sdf = new SimpleDateFormat("MM-dd");
break;
case HHmm:
sdf = new SimpleDateFormat("HH:mm");
break;
default:
sdf = new SimpleDateFormat("yyyy-MM-dd");
break;
}
return sdf;
}
/**
* 将时间字符串转化为date
*/
public static Date parseTime(String dateStr, String formatStr) {
Date date = null;
try {
DateFormat sdf = new SimpleDateFormat(formatStr);
date = sdf.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
/**
* 将字符串转换成date
*/
public static Date parseTime(String time) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
try {
date = sdf.parse(time);
} catch (Exception e) {
e.printStackTrace();
}
return date;
}
/**
* 将字符串转换成date
*/
public static Date parseTime(String time, FormatType type) {
Date date = null;
SimpleDateFormat sdf = getSimpleDateFormat(type);
try {
date = sdf.parse(time);
} catch (Exception e) {
e.printStackTrace();
}
return date;
}
/**
* 增/减 offset 后的日期
*/
public static Date addAndSubtractDate(int offset, Date date, int unit) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
if (unit == Calendar.MONTH) {
calendar.set(Calendar.DATE, 1);
}
calendar.set(unit, calendar.get(unit) + offset);
return calendar.getTime();
}
/**
* 计算两个日期之间相差的天数
*/
public static int daysBetween(Date smdate, Date bdate) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
smdate = sdf.parse(sdf.format(smdate));
bdate = sdf.parse(sdf.format(bdate));
Calendar cal = Calendar.getInstance();
cal.setTime(smdate);
long time1 = cal.getTimeInMillis();
cal.setTime(bdate);
long time2 = cal.getTimeInMillis();
long between_days = (time2 - time1) / (1000 * 3600 * 24);
return Integer.parseInt(String.valueOf(between_days));
}
/**
* 比较日期大小
*/
public static int compareDate(Date smdate, Date bdate) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
smdate = sdf.parse(sdf.format(smdate));
bdate = sdf.parse(sdf.format(bdate));
Calendar cal = Calendar.getInstance();
cal.setTime(smdate);
long time1 = cal.getTimeInMillis();
cal.setTime(bdate);
long time2 = cal.getTimeInMillis();
if (time1 == time2) {
return 0;
} else if (time1 > time2) {
return -1;
} else {
return 1;
}
}
/**
* 根据日期算周几
*/
public static String whatDay(Date date) {
Calendar calendar = Calendar.getInstance();// 获得一个日历
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DATE);
calendar.set(year, month, day);// 设置当前时间,月份是从0月开始计算
int number = calendar.get(Calendar.DAY_OF_WEEK);// 周表示1-7,是从周日开始,
String[] str = {"", "周日", "周一", "周二", "周三", "周四", "周五", "周六",};
return str[number];
}
public static String formatSecondToHourMinuteSecond(int second) {
int h = 0;
int d = 0;
int s = 0;
int temp = second % 3600;
if (second > 3600) {
h = second / 3600;
if (temp != 0) {
if (temp > 60) {
d = temp / 60;
if (temp % 60 != 0) {
s = temp % 60;
}
} else {
s = temp;
}
}
} else {
d = second / 60;
if (second % 60 != 0) {
s = second % 60;
}
}
return h + "时" + d + "分" + s + "秒";
}
public static String formatSecondToHourMinute(int duration) {
if (duration < 60) {
return duration + "秒";
} else if (duration < 60 * 60) {
return Math.round((float) duration / 60) + "分钟";
} else {
int second = duration % (60 * 60);
if (second == 0) {
return (duration / (60 * 60)) + "小时";
} else {
int round = Math.round((float) second / 60);
if (round == 0) {
return (duration / (60 * 60)) + "小时";
} else {
if (round == 60) {
return ((duration / (60 * 60)) + 1) + "小时";
} else {
return (duration / (60 * 60)) + "小时" + round + "分钟";
}
}
}
}
}
/**
* 说明 小于1分钟:”刚刚“ 小于1小时:”X分钟前“ 小于一天:”X小时前“ 小于一月:”X天前“ 小于一年:6-23 大于一年:2015-6-23
*
* @param dateStr
* @return
*/
public static String formatTimeToDay(String dateStr) {
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
DateFormat sdf2 = new SimpleDateFormat("MM-dd");
DateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = sdf.parse(dateStr);
int minute = (int) ((System.currentTimeMillis() - date.getTime()) / 1000 / 60);
if (minute <= 0) {
return "刚刚";
} else if (minute / 60 == 0) {
return minute + "分钟前";
} else if (minute / (60 * 24) == 0) {
return minute / 60 + "小时前";
} else if (minute / (60 * 24 * 30) == 0) {
return minute / (60 * 24) + "天前";
} else if (minute / (60 * 24 * 30 * 12) == 0) {
return sdf2.format(date);
} else {
return sdf3.format(date);
}
} catch (Exception e) {
e.printStackTrace();
}
return dateStr;
}
/**
* 获取几个小时以后的时间戳
*
* @param hour
* @return
*/
public static String getLaterTimeByHour(int hour) {
Date d = new Date();
Calendar now = Calendar.getInstance();
now.setTime(d);
now.set(Calendar.HOUR, now.get(Calendar.HOUR) + hour);
// now.set(Calendar.MINUTE, now.get(Calendar.MINUTE) + 30);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(now.getTime());
}
/**
* 获取几天以后的时间戳
*
* @param day
* @return
*/
public static String getLaterTimeByDay(int day) {
return getLaterTimeByHour(day * 24);
}
}
\ No newline at end of file
package com.fly.tour.common.util;
import android.content.Context;
import com.fly.tour.common.BaseApplication;
/**
* Description: <单位转换工具类><br>
* Author: gxl<br>
* Date: 2018/6/11<br>
* Version: V1.0.0<br>
* Update: <br>
* <ul>
* <h1>功能列表:</h1>
* <li>1. dp转px</li>
* <li>2. px转dp</li>
* <li>3. sp转px</li>
* <li>4. px转sp</li>
* </ul>
*/
public class DisplayUtil {
private static Context context = BaseApplication.getInstance().getApplicationContext();
/**
* 将px值转换为dip或dp值,保证尺寸大小不变
*
* @param pxValue
* @param scale
* (DisplayMetrics类中属性density)
* @return
*/
public static int px2dip(float pxValue, float scale) {
return (int) (pxValue / scale + 0.5f);
}
/**
* 将px值转换为dip或dp值,保证尺寸大小不变
*
* @param pxValue
* (DisplayMetrics类中属性density)
* @return
*/
public static int px2dip(float pxValue) {
return (int) (pxValue / context.getResources().getDisplayMetrics().density + 0.5f);
}
/**
* 将dip或dp值转换为px值,保证尺寸大小不变
*
* @param dipValue
* @param scale
* (DisplayMetrics类中属性density)
* @return
*/
public static int dip2px(float dipValue, float scale) {
return (int) (dipValue * scale + 0.5f);
}
/**
* 将dip或dp值转换为px值,保证尺寸大小不变
*
* @param dipValue
* @return
*/
public static int dip2px(float dipValue) {
return (int) (dipValue * context.getResources().getDisplayMetrics().density + 0.5f);
}
/**
* 将px值转换为sp值,保证文字大小不变
*
* @param pxValue
* @param fontScale
* (DisplayMetrics类中属性scaledDensity)
* @return
*/
public static int px2sp(float pxValue, float fontScale) {
return (int) (pxValue / fontScale + 0.5f);
}
/**
* 将px值转换为sp值,保证文字大小不变
*
* @param pxValue
* @return
*/
public static int px2sp(float pxValue) {
return (int) (pxValue / context.getResources().getDisplayMetrics().scaledDensity + 0.5f);
}
/**
* 将sp值转换为px值,保证文字大小不变
*
* @param spValue
* @param fontScale
* (DisplayMetrics类中属性scaledDensity)
* @return
*/
public static int sp2px(float spValue, float fontScale) {
return (int) (spValue * fontScale + 0.5f);
}
/**
* 将sp值转换为px值,保证文字大小不变
*
* @param spValue
* @return
*/
public static int sp2px(float spValue) {
return (int) (spValue * context.getResources().getDisplayMetrics().scaledDensity + 0.5f);
}
}
\ No newline at end of file
package com.fly.tour.common.util;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Locale;
/**
* Description: <单位转换工具类><br>
* <ul>
* <h1>基本功能:</h1>
* <li>1.获取包名</li>
* <li>2.获取当前应用的版本号</li>
* <li>3.获取当前应用的版本名称</li>
* <li>4.获取应用的名称</li>
* <li>5.获取assets下资源</li>
* <li>6.获取系统语言</li>
* <li>7.获取assets下资源</li>
* <li>8.app的是否在运行</li>
* <li>9.app是否在前台运行</li>
* <li>10.当前Activity是否在栈顶></li>
* <li>11.启动应用</li>
* <li>12.获取assets下资源</li>
* <h1>存贮相关</h1>
* <li>1.外部存储是否可读写</li>
* <li>2.获取外部存储文件夹</li>
* <li>3.获取外部存储路径</li>
* <h1>APK相关操作</h1>
* <li>1.安装APK</li>
* <li>2.卸载APK</li>
* <li>3.获得APK包名</li>
* <li>4.判断是否已经安装</li>
* </ul>
* Author: gxl<br>
* Date: 2018/6/11<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class EnvironmentUtil{
private static final String TAG = "EnvironmentUtil";
/**
* 获取包名
*
* @return 包名
*/
public static String getPackageName(Context context) {
return context.getPackageName();
}
/**
* 获取当前应用的版本号
*/
public static int getAppVersionCode(Context context) {
// 获取手机的包管理者
PackageManager pm = context.getPackageManager();
try {
PackageInfo packInfo = pm.getPackageInfo(getPackageName(context), 0);
return packInfo.versionCode;
} catch (NameNotFoundException e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取当前应用的版本名称
*/
public static String getAppVersionName(Context context) {
// 获取手机的包管理者
PackageManager pm = context.getPackageManager();
try {
PackageInfo packInfo = pm.getPackageInfo(getPackageName(context), 0);
return packInfo.versionName;
} catch (NameNotFoundException e) {
e.printStackTrace();
// 不可能发生.
return "";
}
}
/**
* 获取应用的名称
*
* @return
*/
public static String getApplicationName(Context context) {
PackageManager packageManager = null;
ApplicationInfo applicationInfo = null;
try {
packageManager = context.getPackageManager();
applicationInfo = packageManager.getApplicationInfo(getPackageName(context), 0);
} catch (NameNotFoundException e) {
applicationInfo = null;
}
String applicationName = (String) packageManager.getApplicationLabel(applicationInfo);
System.out.println(applicationName);
return applicationName;
}
/**
* 获取assets下资源
*
* @param context
* @param fileName
* @return
*/
public static String getAssetsString(Context context, String fileName) {
StringBuilder stringBuilder = new StringBuilder();
try {
AssetManager assetManager = context.getAssets();
BufferedReader bf = new BufferedReader(new InputStreamReader(assetManager.open(fileName)));
String line;
while ((line = bf.readLine()) != null) {
stringBuilder.append(line);
}
bf.close();
} catch (IOException e) {
e.printStackTrace();
}
return stringBuilder.toString();
}
/**
* 获取系统语言
*
* @param context
* @return
* @param context
* @return
*/
public static String getSystemLanguage(Context context) {
Locale locale = context.getResources().getConfiguration().locale;
String language = locale.getLanguage();
return language;
}
/**
* 当前app的是否在运行
*
* @return false: 说明app不在当前系统的栈中; true:当前app正处于用户使用状态(包含在Home在后台)
*/
public boolean isAppRunning(Context context) {
ActivityManager activityManager = (ActivityManager) (context.getSystemService(Context.ACTIVITY_SERVICE));
List<ActivityManager.RunningTaskInfo> runningTaskInfos = activityManager.getRunningTasks(100);
if (runningTaskInfos == null) {
return false;
}
for (ActivityManager.RunningTaskInfo taskInfo : runningTaskInfos)
if (context.getPackageName().equals(taskInfo.baseActivity.getPackageName())) {
return true;
}
return false;
}
/**
* app是否在前台
*
* @param context
* @return
*/
public static boolean isForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(context.getPackageName())) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
return true;
} else {
return false;
}
}
}
return false;
}
/**
* 判断当前Activity是否排在栈顶
*
* @return
*/
protected boolean isTopActivity(Context context, Class clazz) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> runningTaskInfos = manager.getRunningTasks(1);
if (runningTaskInfos != null && !runningTaskInfos.isEmpty()
&& clazz.getName().equals(runningTaskInfos.get(0).topActivity.getClassName())) {
return true;
} else {
return false;
}
}
/**
* 返回app运行状态 1:程序在前台运行 2:程序在后台运行 3:程序未启动 注意:需要配置权限<uses-permission
* android:name="android.permission.GET_TASKS" />
*/
public static int getAppStatus(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> list = am.getRunningTasks(20);
// 判断程序是否在栈顶
if (list.get(0).topActivity.getPackageName().equals(context.getPackageName())) {
return 1;
} else {
// 判断程序是否在栈里
for (ActivityManager.RunningTaskInfo info : list) {
if (info.topActivity.getPackageName().equals(context.getPackageName())) {
return 2;
}
}
return 3;// 栈里找不到,返回3
}
}
/**
* 启动应用
*
* @param context
* @param className
*/
public static void openApp(Context context, String className) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
ComponentName cn = new ComponentName(context.getPackageName(), className);
intent.setComponent(cn);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
}
/**
* 存储信息
*/
public static class Storage {
/**
* 外部存储是否可读写
*
* @return 可读写返回true, 否则返回false
*/
public static boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state);
}
/**
* 获取外部目录缓存路径
*
* @param context
* context
* @return 外部存储换成路径
*/
public static File getExternalCacheDir(Context context) {
File file = null;
if (SdkVersionUtil.hasFroyo()) {
file = context.getExternalCacheDir();
}
if (file == null) {
final String cacheDir = "/Android/data/" + context.getPackageName() + "/cache/";
file = new File(Environment.getExternalStorageDirectory().getPath() + cacheDir);
file.mkdirs();
if (file.isDirectory()) {
return file;
}
}
return null;
}
/**
* 获取缓存路径
*
* @param context
* context
* @return 存储路径
*/
public static String getCachePath(Context context) {
File file = null;
if (isExternalStorageWritable()) {
file = getExternalCacheDir(context);
}
return (file != null) ? file.getAbsolutePath() : context.getCacheDir().getAbsolutePath();
}
}
/**
* APK相关操作
*/
public static class Package {
/**
* 安装APK
*
* @param context
* @param file
*/
public static void installApp(Context context, File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
context.startActivity(intent);
}
/**
* 卸载APK
*
* @param context
* @param packageName
*/
public static void unInstallApp(Context context, String packageName) {
Uri packageUri = Uri.parse("package:" + packageName);
Intent intent = new Intent(Intent.ACTION_DELETE, packageUri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
/**
* 获得APK包名
*
* @param context
* @param apkFile
* @return
*/
public static String getApkFilePackage(Context context, File apkFile) {
PackageManager pm = context.getPackageManager();
PackageInfo info = pm.getPackageArchiveInfo(apkFile.getPath(), PackageManager.GET_ACTIVITIES);
if (info != null) {
return info.applicationInfo.packageName;
}
return null;
}
/**
* 判断是否已经安装
*
* @param context
* @param packageName
* @return
*/
public static boolean isAppInstalled(Context context, String packageName) {
if (TextUtils.isEmpty(packageName))
return false;
try {
context.getPackageManager().getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
return true;
} catch (NameNotFoundException e) {
return false;
}
}
}
}
\ No newline at end of file
package com.fly.tour.common.util;
import android.text.TextUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Description: <ToastUtil><br>
* Author: gxl<br>
* Date: 2018/6/11<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class InfoVerify {
/**
* 校验邮箱
*
* @param paramString
* @return
*/
public static boolean isValidEmail(String paramString) {
String regex = "[a-zA-Z0-9_\\.]{1,}@(([a-zA-z0-9]-*){1,}\\.){1,3}[a-zA-z\\-]{1,}";
if (paramString.matches(regex)) {
return true;
} else {
return false;
}
}
/**
* 校验QQ
*
* @param paramString
* @return
*/
public static boolean isValidQQ(String paramString) {
String regex = "^[1-9](\\d){4,9}$";
if (paramString.matches(regex)) {
return true;
}
return false;
}
/**
* 校验车牌号
*
* @param paramString
* @return
*/
public static boolean isValidPlatnum(String paramString) {
if (TextUtils.isEmpty(paramString)) return false;
String regex = "^[\u4e00-\u9fa5]{1}[A-Z_a-z]{1}[A-Z_0-9_a-z]{5}$";
if (paramString.matches(regex)) {
return true;
}
return false;
}
/**
* 校验手机号
*
* @param paramString
* @return
*/
public static boolean isValidMobiNumber(String paramString) {
// String regex = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";
if (paramString == null) return false;
String regex = "^1\\d{10}$";
if (paramString.matches(regex)) {
return true;
}
return false;
}
public static boolean isNumeric(String str) {
Pattern pattern = Pattern.compile("^[0-9]+\\.?[0-9]*[0-9]$");
Matcher isNum = pattern.matcher(str);
return isNum.matches();
}
}
\ No newline at end of file
package com.fly.tour.common.util;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import com.tbruyelle.rxpermissions2.RxPermissions;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import io.reactivex.functions.Consumer;
import me.nereo.multi_image_selector.MultiImageSelector;
/**
* Description: <h3>多媒体工具类</h3>
* <ul>
* <li>1.图片选择器,可算多张图片</li>
* <li>2.拍照</li>
* <li>3.拍视频</li>
* <li>4.创建一个图片路径</li>
* <li>5.创建一个视频路径</li>
* </ul>
* <h3>注意事项:</h3>
* <ul><li>1. 拍照、拍视频、选择图片完成的回调都在onActivityResult中回调的</l1>
* <li>2.选择图片获取:List<String> path = data.getStringArrayListExtra(MultiImageSelectorActivity.EXTRA_RESULT)</li>
* </ul>
* Author: gxl<br>
* Date: 2018/12/25<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class MultiMediaUtil {
public static final int SELECT_IMAGE = 1001;
public static final int TAKE_PHONE = 1002;
public static final int TAKE_VIDEO = 1003;
/**
*
* 打开图片选择器,选择图片<br>
* 来获取图片
* @param activity
* @param count:选择图片个数
* @param requestcode
*/
public static void pohotoSelect(Activity activity, int count, int requestcode) {
pohotoSelect(activity, null, count, requestcode);
}
public static void pohotoSelect(Fragment fragment, int count, int requestcode) {
pohotoSelect(null, fragment, count, requestcode);
}
private static void pohotoSelect(Activity activity, Fragment fragment, int count, int requestcode) {
if (activity != null) {
MultiImageSelector.create().showCamera(false).count(count).single().multi()
//.origin(ArrayList<String>)
.start(activity, requestcode);
} else if (fragment != null) {
MultiImageSelector.create().showCamera(false).count(count).single().multi()
//.origin(ArrayList<String>)
.start(fragment, requestcode);
}
}
/**
* 拍照
* @param activity
* @param path:照片存放的路径
* @param requestcode
*/
public static void takePhoto(FragmentActivity activity, String path, int requestcode) {
takePhoto(activity, null, path, requestcode);
}
public static void takePhoto(Fragment fragment, String path, int requestcode) {
takePhoto(null, fragment, path, requestcode);
}
private static void takePhoto(final FragmentActivity activity, final Fragment fragment, final String path, final int requestcode) {
if (activity == null && fragment == null) {
return;
}
RxPermissions rxPermissions = null;
if (activity != null) {
rxPermissions = new RxPermissions(activity);
} else if (fragment != null) {
rxPermissions = new RxPermissions(fragment);
}
rxPermissions.request(Manifest.permission.CAMERA).subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean aBoolean) throws Exception {
if (aBoolean) {
File file = new File(path);
try {
if (file.createNewFile()) {
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
if (activity != null) {
activity.startActivityForResult(intent, requestcode);
} else if (fragment != null) {
fragment.startActivityForResult(intent, requestcode);
}
}
} catch (Exception e) {
e.printStackTrace();
ToastUtil.showToast("无法启动拍照程序");
}
} else {
ToastUtil.showToast("无摄像头权限,无法进行拍照!");
}
}
});
}
/**
* 拍视频
* @param activity
* @param path:视频存放的路径
* @param requestcode
*/
public static void takeVideo(final FragmentActivity activity, final String path, final int requestcode) {
takeVideo(activity, null, path, requestcode);
}
public static void takeVideo(final Fragment fragment, final String path, final int requestcode) {
takeVideo(null, fragment, path, requestcode);
}
private static void takeVideo(final FragmentActivity activity, final Fragment fragment, final String path, final int requestcode) {
if (activity == null && fragment == null) {
return;
}
RxPermissions rxPermissions = null;
if (activity != null) {
rxPermissions = new RxPermissions(activity);
} else if (fragment != null) {
rxPermissions = new RxPermissions(fragment);
}
rxPermissions.request(Manifest.permission.CAMERA).subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean aBoolean) throws Exception {
if (aBoolean) {
File file = new File(path);
try {
if (file.createNewFile()) {
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_VIDEO_CAPTURE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
if (activity != null) {
activity.startActivityForResult(intent, requestcode);
} else if (fragment != null) {
fragment.startActivityForResult(intent, requestcode);
}
}
} catch (Exception e) {
e.printStackTrace();
ToastUtil.showToast("无法启动拍视频程序");
}
} else {
ToastUtil.showToast("无摄像头权限,无法进行拍视频!");
}
}
});
}
//获取图片路径
public static String getPhotoPath(Activity activity) {
String filename = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + ".jpg";
String filepath = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath() + File.separator + filename;
return filepath;
}
//获取视频的路径
public static String getVideoPath(Activity activity) {
String filename = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + ".3gp";
String filepath = activity.getExternalFilesDir(Environment.DIRECTORY_MOVIES).getAbsolutePath() + File.separator + filename;
return filepath;
}
}
package com.fly.tour.common.util;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.annotation.NonNull;
import com.fly.tour.common.BaseApplication;
/**
* Description: <ToastUtil><br>
* Author: gxl<br>
* Date: 2018/6/11<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class NetUtil {
public static boolean checkNet() {
Context context = BaseApplication.getInstance();
return isWifiConnection(context) || isStationConnection(context);
}
public static boolean checkNetToast() {
boolean isNet = checkNet();
if (!isNet) {
ToastUtil.showToast("网络不给力哦!");
}
return isNet;
}
/**
* 是否使用基站联网
*
* @param context
* @return
*/
public static boolean isStationConnection(@NonNull Context context) {
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (manager == null) {
return false;
}
NetworkInfo networkInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (networkInfo != null) {
return networkInfo.isAvailable() && networkInfo.isConnected();
}
return false;
}
/**
* 是否使用WIFI联网
*
* @param context
* @return
*/
public static boolean isWifiConnection(@NonNull Context context) {
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (manager == null) {
return false;
}
NetworkInfo networkInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (networkInfo != null) {
return networkInfo.isAvailable() && networkInfo.isConnected();
}
return false;
}
}
\ No newline at end of file
package com.fly.tour.common.util;
import java.math.BigDecimal;
/**
* Description: <数字格式化工具类><br>
* Author: gxl<br>
* Date: 2018/12/17<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class NumberUtils {
/**
* 格式化为指定位小数的数字,返回未使用科学计数法表示的具有指定位数的字符串。
* 该方法舍入模式:向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。
* <pre>
* "3.1415926", 1 --> 3.1
* "3.1415926", 3 --> 3.142
* "3.1415926", 4 --> 3.1416
* "3.1415926", 6 --> 3.141593
* "1234567891234567.1415926", 3 --> 1234567891234567.142
* </pre>
* @param number 类型的数字对象
* @param precision 小数精确度总位数,如2表示两位小数
* @return 返回数字格式化后的字符串表示形式(注意返回的字符串未使用科学计数法)
*/
public static String keepPrecision(String number, int precision) {
BigDecimal bg = new BigDecimal(number);
return bg.setScale(precision, BigDecimal.ROUND_HALF_UP).toPlainString();
}
/**
* 格式化为指定位小数的数字,返回未使用科学计数法表示的具有指定位数的字符串。<br>
* 该方法舍入模式:向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。<br>
* 如果给定的数字没有小数,则转换之后将以0填充;例如:int 123 1 --> 123.0<br>
* <b>注意:</b>如果精度要求比较精确请使用 keepPrecision(String number, int precision)方法
* @param number 类型的数字对象
* @param precision 小数精确度总位数,如2表示两位小数
* @return 返回数字格式化后的字符串表示形式(注意返回的字符串未使用科学计数法)
*/
public static String keepPrecision(Number number, int precision) {
return keepPrecision(String.valueOf(number), precision);
}
public static double keepPrecision(double number, int precision) {
BigDecimal bg = new BigDecimal(number);
return bg.setScale(precision, BigDecimal.ROUND_HALF_UP).doubleValue();
}
public static float keepPrecision(float number, int precision) {
BigDecimal bg = new BigDecimal(number);
return bg.setScale(precision, BigDecimal.ROUND_HALF_UP).floatValue();
}
}
package com.fly.tour.common.util;
/**
* Description: <动态获取资源id><br>
* Author: gxl<br>
* Date: 2018/6/19<br>
* Version: V1.0.0<br>
* Update: <br>
*/
import android.content.Context;
public class ResIdUtil {
/**
* 获取id
*
* @param resName 资源名称
* @return 资源id
*/
public static int id(Context context, String resName) {
return context.getResources().getIdentifier(resName, "id", context.getPackageName());
}
/**
* 获取anim类型资源id
*
* @param resName 资源名称
* @return 资源id
*/
public static int anim(Context context, String resName) {
return context.getResources().getIdentifier(resName, "anim", context.getPackageName());
}
/**
* 获取layout类型资源id
*
* @param resName 资源名称
* @return 资源id
*/
public static int layout(Context context, String resName) {
return context.getResources().getIdentifier(resName, "layout", context.getPackageName());
}
/**
* 获取drawable类型资源id
*
* @param resName 资源名称
* @return 资源id
*/
public static int drawable(Context context, String resName) {
return context.getResources().getIdentifier(resName, "drawable", context.getPackageName());
}
/**
* 获取string类型资源id
*
* @param resName 资源名称
* @return 资源id
*/
public static int string(Context context, String resName) {
return context.getResources().getIdentifier(resName, "string", context.getPackageName());
}
/**
* 获取raw类型资源id
*
* @param resName 资源名称
* @return 资源id
*/
public static int raw(Context context, String resName) {
return context.getResources().getIdentifier(resName, "raw", context.getPackageName());
}
/**
* 获取style类型资源id
*
* @param resName 资源名称
* @return 资源id
*/
public static int style(Context context, String resName) {
return context.getResources().getIdentifier(resName, "style", context.getPackageName());
}
}
\ No newline at end of file
package com.fly.tour.common.util;
/**
* Description: <SPUtils><br>
* Author: gxl<br>
* Date: 2018/6/19<br>
* Version: V1.0.0<br>
* Update: <br>
* <ul>
* <li>1.缓存数据</li>
* <li>2.获取数据</li>
* <li>3.删除数据</li>
* <li>4.清空数据</li>
* </ul>
*/
import android.content.Context;
import android.content.SharedPreferences;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
public class SPUtils {
/**
* 保存在手机里面的文件名
*/
public static final String FILE_NAME = "sp_data";
/**
* 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
*
* @param context
* @param key
* @param object
*/
public static void put(Context context, String key, Object object) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
if (object instanceof String) {
editor.putString(key, (String) object);
} else if (object instanceof Integer) {
editor.putInt(key, (Integer) object);
} else if (object instanceof Boolean) {
editor.putBoolean(key, (Boolean) object);
} else if (object instanceof Float) {
editor.putFloat(key, (Float) object);
} else if (object instanceof Long) {
editor.putLong(key, (Long) object);
} else {
editor.putString(key, object.toString());
}
SharedPreferencesCompat.apply(editor);
}
/**
* 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值
*
* @param context
* @param key
* @param defaultObject
* @return
*/
public static Object get(Context context, String key, Object defaultObject) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
if (defaultObject instanceof String) {
return sp.getString(key, (String) defaultObject);
} else if (defaultObject instanceof Integer) {
return sp.getInt(key, (Integer) defaultObject);
} else if (defaultObject instanceof Boolean) {
return sp.getBoolean(key, (Boolean) defaultObject);
} else if (defaultObject instanceof Float) {
return sp.getFloat(key, (Float) defaultObject);
} else if (defaultObject instanceof Long) {
return sp.getLong(key, (Long) defaultObject);
}
return null;
}
/**
* 移除某个key值已经对应的值
*
* @param context
* @param key
*/
public static void remove(Context context, String key) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.remove(key);
SharedPreferencesCompat.apply(editor);
}
/**
* 清除所有数据
*
* @param context
*/
public static void clear(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.clear();
SharedPreferencesCompat.apply(editor);
}
/**
* 查询某个key是否已经存在
*
* @param context
* @param key
* @return
*/
public static boolean contains(Context context, String key) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
return sp.contains(key);
}
/**
* 返回所有的键值对
*
* @param context
* @return
*/
public static Map<String, ?> getAll(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
return sp.getAll();
}
/**
* 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类
*
* @author zhy
*/
private static class SharedPreferencesCompat {
private static final Method sApplyMethod = findApplyMethod();
/**
* 反射查找apply的方法
*
* @return
*/
@SuppressWarnings({"unchecked", "rawtypes"})
private static Method findApplyMethod() {
try {
Class clz = SharedPreferences.Editor.class;
return clz.getMethod("apply");
} catch (NoSuchMethodException e) {}
return null;
}
/**
* 如果找到则使用apply执行,否则使用commit
*
* @param editor
*/
public static void apply(SharedPreferences.Editor editor) {
try {
if (sApplyMethod != null) {
sApplyMethod.invoke(editor);
return;
}
} catch (IllegalArgumentException e) {} catch (IllegalAccessException e) {} catch (InvocationTargetException e) {}
editor.commit();
}
}
}
package com.fly.tour.common.util;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;
/**
* Created by sendtion on 2016/5/25.
*/
public class ScreenUtils {
/**
* 获得屏幕宽度
* @param context
* @return
*/
public static int getScreenWidth(Context context)
{
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.widthPixels;
}
/**
* 获得屏幕高度
* @param context
* @return
*/
public static int getScreenHeight(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.heightPixels;
}
/**
* 获得状态栏高度
* @param context
* @return
*/
public static int getStatusHeight(Context context) {
int statusHeight = -1;
try {
Class<?> clazz = Class.forName("com.android.internal.R$dimen");
Object object = clazz.newInstance();
int height = Integer.parseInt(clazz.getField("status_bar_height")
.get(object).toString());
statusHeight = context.getResources().getDimensionPixelSize(height);
} catch (Exception e) {
e.printStackTrace();
}
return statusHeight;
}
/**
* 获取当前屏幕截图,包含状态栏
*/
public static Bitmap snapShotWithStatusBar(Activity activity){
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
int width = getScreenWidth(activity);
int height = getScreenHeight(activity);
Bitmap bp = null;
bp = Bitmap.createBitmap(bmp, 0, 0, width, height);
view.destroyDrawingCache();
return bp;
}
/**
* 获取当前屏幕截图,不包含状态栏
*
*/
public static Bitmap snapShotWithoutStatusBar(Activity activity){
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
Rect frame = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
int width = getScreenWidth(activity);
int height = getScreenHeight(activity);
Bitmap bp = null;
bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height
- statusBarHeight);
view.destroyDrawingCache();
return bp;
}
}
\ No newline at end of file
package com.fly.tour.common.util;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
/**
* 版本相关
*/
public class SdkVersionUtil {
/**
* hasForyo
*
* @return true false
*/
public static boolean hasFroyo() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
}
/**
* hasGingerbread
*
* @return true false
*/
public static boolean hasGingerbread() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
}
/**
* hasHoneycomb
*
* @return true false
*/
public static boolean hasHoneycomb() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
}
/**
* hasHoneycombMR1
*
* @return true false
*/
public static boolean hasHoneycombMR1() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1;
}
/**
* hasHoneycombMR2
*
* @return true false
*/
public static boolean hasHoneycombMR2() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2;
}
/**
* hasIceCreamSandwich
*
* @return true false
*/
public static boolean hasIceCreamSandwich() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
}
/**
* hasJellyBean
*
* @return true false
*/
public static boolean hasJellyBean() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
}
/**
* 4.2以上
*
* @return true false
*/
public static boolean aboveJellyBean() {
return Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN;
}
public static int getAppVersion(Context context) {
int version = 0;
try {
version = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return version;
}
}
\ No newline at end of file
package com.fly.tour.common.util;
import android.content.Context;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
/**
* Description: <软键盘的显示与隐藏><br>
* Author: gxl<br>
* Date: 2018/6/11<br>
* Version: V1.0.0<br>
* Update: <br>
* <ul>
* <li>1.显示软键盘</li>
* <li>2.隐藏软键盘</li>
* </ul>
*/
public class SoftInputUtil {
/**
* 显示软键盘
*
* @param context
*/
public static void showSoftInput(Context context) {
InputMethodManager imm =
(InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); // 显示软键盘
imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
}
/**
* 显示软键盘
*
* @param context
*/
public static void showSoftInput(Context context, View view) {
InputMethodManager imm =
(InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); // 显示软键盘
imm.showSoftInput(view, 0);
}
/**
* 隐藏软键盘
*
* @param context
* @param view
*/
public static void hideSoftInput(Context context, View view) {
InputMethodManager immHide =
(InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); // 隐藏软键盘
immHide.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
\ No newline at end of file
package com.fly.tour.common.util;
import android.widget.Toast;
import com.fly.tour.common.BaseApplication;
/**
* Description: <吐司工具类><br>
* Author: gxl<br>
* Date: 2018/6/11<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class ToastUtil {
public static void showToast(String message) {
Toast.makeText(BaseApplication.getInstance(), message, Toast.LENGTH_SHORT).show();
}
public static void showToast(int resid) {
Toast.makeText(BaseApplication.getInstance(), BaseApplication.getInstance().getString(resid), Toast.LENGTH_SHORT)
.show();
}
}
\ No newline at end of file
package com.fly.tour.common.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.TextView;
/**
* Description: <文字图标居中TextView><br>
* Author: gxl<br>
* Date: 2018/8/24<br>
* Version: V1.0.0<br>
* Update: <br>
*/
@SuppressLint("AppCompatCustomView")
public class DrawableCenterTextView extends TextView {
public DrawableCenterTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public DrawableCenterTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DrawableCenterTextView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
Drawable[] drawables = getCompoundDrawables();
if (drawables != null) {
Drawable drawableLeft = drawables[0];
if (drawableLeft != null) {
float textWidth = getPaint().measureText(getText().toString());
int drawablePadding = getCompoundDrawablePadding();
int drawableWidth = 0;
drawableWidth = drawableLeft.getIntrinsicWidth();
float bodyWidth = textWidth + drawableWidth + drawablePadding;
float v = getWidth() - bodyWidth;
if (v > 0)
canvas.translate(v / 2, 0);
else
canvas.translate(0, 0);
}
}
super.onDraw(canvas);
}
}
\ No newline at end of file
/*
* Copyright (C) 2011 The Android Open Source Project Copyright 2014 Manabu Shimobe
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.fly.tour.common.view;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.support.annotation.DrawableRes;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.SparseBooleanArray;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.fly.tour.common.R;
/**
* 默认展开状态: ExpandableTextView.expandView(); ExpandableTextView.showToogleView(false);
*/
public class ExpandableTextView extends LinearLayout implements View.OnClickListener {
private static final String TAG = ExpandableTextView.class.getSimpleName();
private static final int EXPAND_INDICATOR_IMAGE_BUTTON = 0;
private static final int EXPAND_INDICATOR_TEXT_VIEW = 1;
private static final int DEFAULT_TOGGLE_TYPE = EXPAND_INDICATOR_IMAGE_BUTTON;
/* The default number of lines */
private static final int MAX_COLLAPSED_LINES = 8;
/* The default animation duration */
private static final int DEFAULT_ANIM_DURATION = 300;
/* The default alpha value when the animation starts */
private static final float DEFAULT_ANIM_ALPHA_START = 0.7f;
protected TextView mTv;
protected View mToggleView; // View to expand/collapse
private boolean mRelayout;
private boolean mCollapsed = true; // Show short version as default.
private int mCollapsedHeight;
private int mTextHeightWithMaxLines;
private int mMaxCollapsedLines;
private int mMarginBetweenTxtAndBottom;
private ExpandIndicatorController mExpandIndicatorController;
private int mAnimationDuration;
private float mAnimAlphaStart;
private boolean mAnimating;
@IdRes
private int mExpandableTextId = R.id.expandable_text;
@IdRes
private int mExpandCollapseToggleId = R.id.expand_collapse;
private boolean mExpandToggleOnTextClick;
/* Listener for callback */
private OnExpandStateChangeListener mListener;
/* For saving collapsed status when used in ListView */
private SparseBooleanArray mCollapsedStatus;
private int mPosition;
public ExpandableTextView(Context context) {
this(context, null);
}
public ExpandableTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public ExpandableTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
@Override
public void setOrientation(int orientation) {
if (LinearLayout.HORIZONTAL == orientation) {
throw new IllegalArgumentException("ExpandableTextView only supports Vertical Orientation.");
}
super.setOrientation(orientation);
}
@Override
public void onClick(View view) {
if (mToggleView.getVisibility() != View.VISIBLE) {
return;
}
mCollapsed = !mCollapsed;
mExpandIndicatorController.changeState(mCollapsed);
if (mCollapsedStatus != null) {
mCollapsedStatus.put(mPosition, mCollapsed);
}
// mark that the animation is in progress
mAnimating = true;
Animation animation;
if (mCollapsed) {
animation = new ExpandCollapseAnimation(this, getHeight(), mCollapsedHeight);
} else {
animation = new ExpandCollapseAnimation(this, getHeight(),
getHeight() + mTextHeightWithMaxLines - mTv.getHeight());
}
animation.setFillAfter(true);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
applyAlphaAnimation(mTv, mAnimAlphaStart);
}
@Override
public void onAnimationEnd(Animation animation) {
// clear animation here to avoid repeated applyTransformation() calls
clearAnimation();
// clear the animation flag
mAnimating = false;
// notify the listener
if (mListener != null) {
mListener.onExpandStateChanged(mTv, !mCollapsed);
}
}
@Override
public void onAnimationRepeat(Animation animation) {}
});
clearAnimation();
startAnimation(animation);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// while an animation is in progress, intercept all the touch events to children to
// prevent extra clicks during the animation
return mAnimating;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
findViews();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// If no change, measure and return
if (!mRelayout || getVisibility() == View.GONE) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
mRelayout = false;
// Setup with optimistic case
// i.e. Everything fits. No button needed
mToggleView.setVisibility(View.GONE);
mTv.setMaxLines(Integer.MAX_VALUE);
// Measure
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// If the text fits in collapsed mode, we are done.
if (mTv.getLineCount() <= mMaxCollapsedLines) {
return;
}
// Saves the text height w/ max lines
mTextHeightWithMaxLines = getRealTextViewHeight(mTv);
// Doesn't fit in collapsed mode. Collapse text view as needed. Show
// button.
if (mCollapsed) {
mTv.setMaxLines(mMaxCollapsedLines);
}
mToggleView.setVisibility(View.VISIBLE);
// Re-measure with new setup
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mCollapsed) {
// Gets the margin between the TextView's bottom and the ViewGroup's bottom
mTv.post(new Runnable() {
@Override
public void run() {
mMarginBetweenTxtAndBottom = getHeight() - mTv.getHeight();
}
});
// Saves the collapsed height of this ViewGroup
mCollapsedHeight = getMeasuredHeight();
}
}
public void setOnExpandStateChangeListener(@Nullable OnExpandStateChangeListener listener) {
mListener = listener;
}
public void setText(@Nullable CharSequence text) {
mRelayout = true;
mTv.setText(text);
setVisibility(TextUtils.isEmpty(text) ? View.GONE : View.VISIBLE);
clearAnimation();
getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
requestLayout();
}
public void setText(@Nullable CharSequence text, @NonNull SparseBooleanArray collapsedStatus,
int position) {
mCollapsedStatus = collapsedStatus;
mPosition = position;
boolean isCollapsed = collapsedStatus.get(position, true);
clearAnimation();
mCollapsed = isCollapsed;
mExpandIndicatorController.changeState(mCollapsed);
setText(text);
}
@Nullable
public CharSequence getText() {
if (mTv == null) {
return "";
}
return mTv.getText();
}
private void init(AttributeSet attrs) {
TypedArray typedArray =
getContext().obtainStyledAttributes(attrs, R.styleable.ExpandableTextView);
mMaxCollapsedLines =
typedArray.getInt(R.styleable.ExpandableTextView_maxCollapsedLines, MAX_COLLAPSED_LINES);
mAnimationDuration =
typedArray.getInt(R.styleable.ExpandableTextView_animDuration, DEFAULT_ANIM_DURATION);
mAnimAlphaStart = typedArray.getFloat(R.styleable.ExpandableTextView_animAlphaStart,
DEFAULT_ANIM_ALPHA_START);
mExpandableTextId = typedArray.getResourceId(R.styleable.ExpandableTextView_expandableTextId,
R.id.expandable_text);
mExpandCollapseToggleId = typedArray
.getResourceId(R.styleable.ExpandableTextView_expandCollapseToggleId, R.id.expand_collapse);
mExpandToggleOnTextClick =
typedArray.getBoolean(R.styleable.ExpandableTextView_expandToggleOnTextClick, true);
mExpandIndicatorController = setupExpandToggleController(getContext(), typedArray);
typedArray.recycle();
// enforces vertical orientation
setOrientation(LinearLayout.VERTICAL);
// default visibility is gone
setVisibility(GONE);
}
private void findViews() {
mTv = (TextView) findViewById(mExpandableTextId);
if (mExpandToggleOnTextClick) {
mTv.setOnClickListener(this);
} else {
mTv.setOnClickListener(null);
}
mToggleView = findViewById(mExpandCollapseToggleId);
mExpandIndicatorController.setView(mToggleView);
mExpandIndicatorController.changeState(mCollapsed);
mToggleView.setOnClickListener(this);
}
private static boolean isPostHoneycomb() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
}
private static boolean isPostLolipop() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private static void applyAlphaAnimation(View view, float alpha) {
if (isPostHoneycomb()) {
view.setAlpha(alpha);
} else {
AlphaAnimation alphaAnimation = new AlphaAnimation(alpha, alpha);
// make it instant
alphaAnimation.setDuration(0);
alphaAnimation.setFillAfter(true);
view.startAnimation(alphaAnimation);
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static Drawable getDrawable(@NonNull Context context, @DrawableRes int resId) {
Resources resources = context.getResources();
if (isPostLolipop()) {
return resources.getDrawable(resId, context.getTheme());
} else {
return resources.getDrawable(resId);
}
}
private static int getRealTextViewHeight(@NonNull TextView textView) {
int textHeight = textView.getLayout().getLineTop(textView.getLineCount());
int padding = textView.getCompoundPaddingTop() + textView.getCompoundPaddingBottom();
return textHeight + padding;
}
private ExpandIndicatorController setupExpandToggleController(@NonNull Context context,
TypedArray typedArray) {
final int expandToggleType =
typedArray.getInt(R.styleable.ExpandableTextView_expandToggleType, DEFAULT_TOGGLE_TYPE);
final ExpandIndicatorController expandIndicatorController;
switch (expandToggleType) {
case EXPAND_INDICATOR_IMAGE_BUTTON:
Drawable expandDrawable =
typedArray.getDrawable(R.styleable.ExpandableTextView_expandIndicator);
Drawable collapseDrawable =
typedArray.getDrawable(R.styleable.ExpandableTextView_collapseIndicator);
if (expandDrawable == null) {
expandDrawable = getDrawable(context, R.mipmap.expend_btn);
}
if (collapseDrawable == null) {
collapseDrawable = getDrawable(context, R.mipmap.reduce_btn);
}
expandIndicatorController =
new ImageButtonExpandController(expandDrawable, collapseDrawable);
break;
case EXPAND_INDICATOR_TEXT_VIEW:
String expandText = typedArray.getString(R.styleable.ExpandableTextView_expandIndicator);
String collapseText =
typedArray.getString(R.styleable.ExpandableTextView_collapseIndicator);
expandIndicatorController = new TextViewExpandController(expandText, collapseText);
break;
default:
throw new IllegalStateException(
"Must be of enum: ExpandableTextView_expandToggleType, one of EXPAND_INDICATOR_IMAGE_BUTTON or EXPAND_INDICATOR_TEXT_VIEW.");
}
return expandIndicatorController;
}
class ExpandCollapseAnimation extends Animation {
private final View mTargetView;
private final int mStartHeight;
private final int mEndHeight;
public ExpandCollapseAnimation(View view, int startHeight, int endHeight) {
mTargetView = view;
mStartHeight = startHeight;
mEndHeight = endHeight;
setDuration(mAnimationDuration);
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final int newHeight = (int) ((mEndHeight - mStartHeight) * interpolatedTime + mStartHeight);
mTv.setMaxHeight(newHeight - mMarginBetweenTxtAndBottom);
if (Float.compare(mAnimAlphaStart, 1.0f) != 0) {
applyAlphaAnimation(mTv, mAnimAlphaStart + interpolatedTime * (1.0f - mAnimAlphaStart));
}
mTargetView.getLayoutParams().height = newHeight;
mTargetView.requestLayout();
}
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
@Override
public boolean willChangeBounds() {
return true;
}
}
public interface OnExpandStateChangeListener {
/**
* Called when the expand/collapse animation has been finished
*
* @param textView - TextView being expanded/collapsed
* @param isExpanded - true if the TextView has been expanded
*/
void onExpandStateChanged(TextView textView, boolean isExpanded);
}
interface ExpandIndicatorController {
void changeState(boolean collapsed);
void setView(View toggleView);
void showView(boolean isshow);
}
class ImageButtonExpandController implements ExpandIndicatorController {
private final Drawable mExpandDrawable;
private final Drawable mCollapseDrawable;
private ImageButton mImageButton;
public ImageButtonExpandController(Drawable expandDrawable, Drawable collapseDrawable) {
mExpandDrawable = expandDrawable;
mCollapseDrawable = collapseDrawable;
}
@Override
public void changeState(boolean collapsed) {
mImageButton.setImageDrawable(collapsed ? mExpandDrawable : mCollapseDrawable);
}
@Override
public void setView(View toggleView) {
mImageButton = (ImageButton) toggleView;
}
@Override
public void showView(final boolean isshow) {
if (mImageButton != null) {
new Handler().post(new Runnable() {
@Override
public void run() {
mImageButton.clearAnimation();
mImageButton.setVisibility(isshow ? View.VISIBLE : View.GONE);
}
});
}
}
}
static class TextViewExpandController implements ExpandIndicatorController {
private final String mExpandText;
private final String mCollapseText;
private TextView mTextView;
public TextViewExpandController(String expandText, String collapseText) {
mExpandText = expandText;
mCollapseText = collapseText;
}
@Override
public void changeState(boolean collapsed) {
mTextView.setText(collapsed ? mExpandText : mCollapseText);
}
@Override
public void setView(View toggleView) {
mTextView = (TextView) toggleView;
}
@Override
public void showView(boolean isshow) {
}
}
public void showToogleView(boolean isshow) {
if (mExpandIndicatorController != null) {
mExpandIndicatorController.showView(isshow);
}
}
public void expandView() {
mCollapsed = false;
requestLayout();
}
}
package com.fly.tour.common.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.fly.tour.common.R;
/**
* Description: <><br>
* Author: gxl<br>
* Date: 2018/6/11<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class LoadingView extends RelativeLayout {
private ImageView img_wheel1;
private AnimationDrawable mAnimation;
public LoadingView(Context context) {
this(context, null);
}
public LoadingView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LoadingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView(context);
}
@SuppressLint("ResourceType")
public void onLoading() {
setVisibility(VISIBLE);
img_wheel1.setBackgroundResource(R.anim.loading);
mAnimation = (AnimationDrawable) img_wheel1.getBackground();
mAnimation.start();
}
public void endLoading() {
mAnimation.stop();
}
private void initView(Context context) {
View view = View.inflate(context, R.layout.base_loading, this);
img_wheel1 = (ImageView) view.findViewById(R.id.img_wheel1);
}
}
package com.fly.tour.common.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.View;
import android.widget.TextView;
import com.fly.tour.common.R;
import java.util.ArrayList;
import java.util.WeakHashMap;
/**
*
* https://github.com/m5/MagicTextView
* Description: <描边效果的TextView><br>
* Author: gxl<br>
* Date: 2018/8/24<br>
* Version: V1.0.0<br>
* Update: <br>
*/
@SuppressLint("AppCompatCustomView")
public class MagicTextView extends TextView {
private ArrayList<Shadow> outerShadows;
private ArrayList<Shadow> innerShadows;
private WeakHashMap<String, Pair<Canvas, Bitmap>> canvasStore;
private Canvas tempCanvas;
private Bitmap tempBitmap;
private Drawable foregroundDrawable;
private float strokeWidth;
private Integer strokeColor;
private Join strokeJoin;
private float strokeMiter;
private int[] lockedCompoundPadding;
private boolean frozen = false;
public MagicTextView(Context context) {
super(context);
init(null);
}
public MagicTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public MagicTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
public void init(AttributeSet attrs) {
outerShadows = new ArrayList<Shadow>();
innerShadows = new ArrayList<Shadow>();
if (canvasStore == null) {
canvasStore = new WeakHashMap<String, Pair<Canvas, Bitmap>>();
}
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MagicTextView);
String typefaceName = a.getString(R.styleable.MagicTextView_typeface);
if (typefaceName != null) {
Typeface tf = Typeface.createFromAsset(getContext().getAssets(),
String.format("fonts/%s.ttf", typefaceName));
setTypeface(tf);
}
if (a.hasValue(R.styleable.MagicTextView_foreground)) {
Drawable foreground = a.getDrawable(R.styleable.MagicTextView_foreground);
if (foreground != null) {
this.setForegroundDrawable(foreground);
} else {
this.setTextColor(a.getColor(R.styleable.MagicTextView_foreground, 0xff000000));
}
}
if (a.hasValue(R.styleable.MagicTextView_backgroundcolor)) {
Drawable background = a.getDrawable(R.styleable.MagicTextView_backgroundcolor);
if (background != null) {
this.setBackgroundDrawable(background);
} else {
this.setBackgroundColor(
a.getColor(R.styleable.MagicTextView_backgroundcolor, 0xff000000));
}
}
if (a.hasValue(R.styleable.MagicTextView_innerShadowColor)) {
this.addInnerShadow(a.getDimensionPixelSize(R.styleable.MagicTextView_innerShadowRadius, 0),
a.getDimensionPixelOffset(R.styleable.MagicTextView_innerShadowDx, 0),
a.getDimensionPixelOffset(R.styleable.MagicTextView_innerShadowDy, 0),
a.getColor(R.styleable.MagicTextView_innerShadowColor, 0xff000000));
}
if (a.hasValue(R.styleable.MagicTextView_outerShadowColor)) {
this.addOuterShadow(a.getDimensionPixelSize(R.styleable.MagicTextView_outerShadowRadius, 0),
a.getDimensionPixelOffset(R.styleable.MagicTextView_outerShadowDx, 0),
a.getDimensionPixelOffset(R.styleable.MagicTextView_outerShadowDy, 0),
a.getColor(R.styleable.MagicTextView_outerShadowColor, 0xff000000));
}
if (a.hasValue(R.styleable.MagicTextView_strokeColor)) {
float strokeWidth = a.getDimensionPixelSize(R.styleable.MagicTextView_strokeWidth, 1);
int strokeColor = a.getColor(R.styleable.MagicTextView_strokeColor, 0xff000000);
float strokeMiter = a.getDimensionPixelSize(R.styleable.MagicTextView_strokeMiter, 10);
Join strokeJoin = null;
switch (a.getInt(R.styleable.MagicTextView_strokeJoinStyle, 0)) {
case (0):
strokeJoin = Join.MITER;
break;
case (1):
strokeJoin = Join.BEVEL;
break;
case (2):
strokeJoin = Join.ROUND;
break;
}
this.setStroke(strokeWidth, strokeColor, strokeJoin, strokeMiter);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB
&& (innerShadows.size() > 0 || foregroundDrawable != null)) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
}
public void setStroke(float width, int color, Join join, float miter) {
strokeWidth = width;
strokeColor = color;
strokeJoin = join;
strokeMiter = miter;
}
public void setStroke(float width, int color) {
setStroke(width, color, Join.MITER, 10);
}
public void addOuterShadow(float r, float dx, float dy, int color) {
if (r == 0) {
r = 0.0001f;
}
outerShadows.add(new Shadow(r, dx, dy, color));
}
public void addInnerShadow(float r, float dx, float dy, int color) {
if (r == 0) {
r = 0.0001f;
}
innerShadows.add(new Shadow(r, dx, dy, color));
}
public void clearInnerShadows() {
innerShadows.clear();
}
public void clearOuterShadows() {
outerShadows.clear();
}
public void setForegroundDrawable(Drawable d) {
this.foregroundDrawable = d;
}
public Drawable getForeground() {
return this.foregroundDrawable == null
? this.foregroundDrawable
: new ColorDrawable(this.getCurrentTextColor());
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
freeze();
Drawable restoreBackground = this.getBackground();
Drawable[] restoreDrawables = this.getCompoundDrawables();
int restoreColor = this.getCurrentTextColor();
this.setCompoundDrawables(null, null, null, null);
for (Shadow shadow : outerShadows) {
this.setShadowLayer(shadow.r, shadow.dx, shadow.dy, shadow.color);
super.onDraw(canvas);
}
this.setShadowLayer(0, 0, 0, 0);
this.setTextColor(restoreColor);
if (this.foregroundDrawable != null && this.foregroundDrawable instanceof BitmapDrawable) {
generateTempCanvas();
super.onDraw(tempCanvas);
Paint paint = ((BitmapDrawable) this.foregroundDrawable).getPaint();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
this.foregroundDrawable.setBounds(canvas.getClipBounds());
this.foregroundDrawable.draw(tempCanvas);
canvas.drawBitmap(tempBitmap, 0, 0, null);
tempCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
}
if (strokeColor != null) {
TextPaint paint = this.getPaint();
paint.setStyle(Style.STROKE);
paint.setStrokeJoin(strokeJoin);
paint.setStrokeMiter(strokeMiter);
this.setTextColor(strokeColor);
paint.setStrokeWidth(strokeWidth);
super.onDraw(canvas);
paint.setStyle(Style.FILL);
this.setTextColor(restoreColor);
}
if (innerShadows.size() > 0) {
generateTempCanvas();
TextPaint paint = this.getPaint();
for (Shadow shadow : innerShadows) {
this.setTextColor(shadow.color);
super.onDraw(tempCanvas);
this.setTextColor(0xFF000000);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
paint.setMaskFilter(new BlurMaskFilter(shadow.r, BlurMaskFilter.Blur.NORMAL));
tempCanvas.save();
tempCanvas.translate(shadow.dx, shadow.dy);
super.onDraw(tempCanvas);
tempCanvas.restore();
canvas.drawBitmap(tempBitmap, 0, 0, null);
tempCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
paint.setXfermode(null);
paint.setMaskFilter(null);
this.setTextColor(restoreColor);
this.setShadowLayer(0, 0, 0, 0);
}
}
if (restoreDrawables != null) {
this.setCompoundDrawablesWithIntrinsicBounds(restoreDrawables[0], restoreDrawables[1],
restoreDrawables[2], restoreDrawables[3]);
}
this.setBackgroundDrawable(restoreBackground);
this.setTextColor(restoreColor);
unfreeze();
}
private void generateTempCanvas() {
String key = String.format("%dx%d", getWidth(), getHeight());
Pair<Canvas, Bitmap> stored = canvasStore.get(key);
if (stored != null) {
tempCanvas = stored.first;
tempBitmap = stored.second;
} else {
tempCanvas = new Canvas();
tempBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
tempCanvas.setBitmap(tempBitmap);
canvasStore.put(key, new Pair<Canvas, Bitmap>(tempCanvas, tempBitmap));
}
}
// Keep these things locked while onDraw in processing
public void freeze() {
lockedCompoundPadding = new int[] {getCompoundPaddingLeft(), getCompoundPaddingRight(),
getCompoundPaddingTop(), getCompoundPaddingBottom()};
frozen = true;
}
public void unfreeze() {
frozen = false;
}
@Override
public void requestLayout() {
if (!frozen) super.requestLayout();
}
@Override
public void postInvalidate() {
if (!frozen) super.postInvalidate();
}
@Override
public void postInvalidate(int left, int top, int right, int bottom) {
if (!frozen) super.postInvalidate(left, top, right, bottom);
}
@Override
public void invalidate() {
if (!frozen) super.invalidate();
}
@Override
public void invalidate(Rect rect) {
if (!frozen) super.invalidate(rect);
}
@Override
public void invalidate(int l, int t, int r, int b) {
if (!frozen) super.invalidate(l, t, r, b);
}
@Override
public int getCompoundPaddingLeft() {
return !frozen ? super.getCompoundPaddingLeft() : lockedCompoundPadding[0];
}
@Override
public int getCompoundPaddingRight() {
return !frozen ? super.getCompoundPaddingRight() : lockedCompoundPadding[1];
}
@Override
public int getCompoundPaddingTop() {
return !frozen ? super.getCompoundPaddingTop() : lockedCompoundPadding[2];
}
@Override
public int getCompoundPaddingBottom() {
return !frozen ? super.getCompoundPaddingBottom() : lockedCompoundPadding[3];
}
public static class Shadow {
float r;
float dx;
float dy;
int color;
public Shadow(float r, float dx, float dy, int color) {
this.r = r;
this.dx = dx;
this.dy = dy;
this.color = color;
}
}
}
package com.fly.tour.common.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.RelativeLayout;
import com.fly.tour.common.R;
/**
* Description: <NetworkErrorView><br>
* Author: gxl<br>
* Date: 2018/6/20<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class NetworkErrorView extends RelativeLayout {
public NetworkErrorView(Context context) {
super(context);
init();
}
public NetworkErrorView(Context context, int layoutID) {
super(context);
init();
}
public NetworkErrorView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
LayoutInflater.from(getContext())
.inflate(R.layout.button_network_err, this, true);
this.setClickable(true);
this.setFocusable(true);
}
}
package com.fly.tour.common.view;
import android.animation.ObjectAnimator;
import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.TextView;
import com.fly.tour.common.R;
import com.fly.tour.common.util.DisplayUtil;
/**
* Description: <旋转进度的dialog><br>
* Author: gxl<br>
* Date: 2018/4/19<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class RotateProgressDialog extends DialogFragment {
private TextView mTxtProgress;
private ImageView mImgProgress;
@Override
public void onStart() {
super.onStart();
Dialog dialog = getDialog();
if (dialog != null) {
dialog.getWindow().setLayout(DisplayUtil.dip2px(100), DisplayUtil.dip2px(100));
dialog.setCancelable(false);
dialog.setCanceledOnTouchOutside(false);
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
View view = LayoutInflater.from(getActivity()).inflate(R.layout.rotate_progress_dialog_layout, null,false);
mImgProgress = view.findViewById(R.id.img_progress);
mTxtProgress = view.findViewById(R.id.txt_progress);
//mImgProgress.animate().rotation(360).setDuration(5).r.start();
ObjectAnimator rotation = ObjectAnimator.ofFloat(mImgProgress, "rotation", 0f, 359f);//最好是0f到359f,0f和360f的位置是重复的
rotation.setRepeatCount(ObjectAnimator.INFINITE);
rotation.setInterpolator(new LinearInterpolator());
rotation.setDuration(2000);
rotation.start();
return view;
}
public void setProgress(int value){
mTxtProgress.setText(value+"%");
}
}
package com.fly.tour.common.view;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
/**
* Description: <RecyclerView空白区域点击监听><br>
* Author: gxl<br>
* Date: 2018/8/24<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class TouchyRecyclerView extends RecyclerView {
private OnNoChildClickListener listener;
public TouchyRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public interface OnNoChildClickListener {
public void onNoChildClick();
}
public void setOnNoChildClickListener(OnNoChildClickListener listener) {
this.listener = listener;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN
&& findChildViewUnder(event.getX(), event.getY()) == null) {
if (listener != null) {
listener.onNoChildClick();
}
}
return super.dispatchTouchEvent(event);
}
}
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
<item android:drawable="@mipmap/car01" android:duration="50" />
<item android:drawable="@mipmap/car01_2" android:duration="50" />
<item android:drawable="@mipmap/car02" android:duration="50" />
<item android:drawable="@mipmap/car02_2" android:duration="50" />
<item android:drawable="@mipmap/car03" android:duration="50" />
<item android:drawable="@mipmap/car03_2" android:duration="50" />
<item android:drawable="@mipmap/car04" android:duration="50" />
<item android:drawable="@mipmap/car04_2" android:duration="50" />
<item android:drawable="@mipmap/car05" android:duration="50" />
<item android:drawable="@mipmap/car05_2" android:duration="50" />
<item android:drawable="@mipmap/car06" android:duration="50" />
<item android:drawable="@mipmap/car06_2" android:duration="50" />
</animation-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
<item android:drawable="@mipmap/car01" android:duration="50" />
<item android:drawable="@mipmap/car01_2" android:duration="50" />
<item android:drawable="@mipmap/car02" android:duration="50" />
<item android:drawable="@mipmap/car02_2" android:duration="50" />
<item android:drawable="@mipmap/car03" android:duration="50" />
<item android:drawable="@mipmap/car03_2" android:duration="50" />
<item android:drawable="@mipmap/car04" android:duration="50" />
<item android:drawable="@mipmap/car04_2" android:duration="50" />
<item android:drawable="@mipmap/car05" android:duration="50" />
<item android:drawable="@mipmap/car05_2" android:duration="50" />
<item android:drawable="@mipmap/car06" android:duration="50" />
<item android:drawable="@mipmap/car06_2" android:duration="50" />
</animation-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/ic_menu_back_light" android:state_pressed="true" />
<item android:drawable="@mipmap/ic_menu_back_dark" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#26A69A"
android:pathData="M0,0h108v108h-108z"/>
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8"/>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners android:radius="10dp" />
<solid android:color="#ffffff" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/layout_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay"
app:elevation="0dp">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary">
<ImageButton
android:id="@+id/toolbar_btn_left"
style="@style/AppTheme.ImageButton"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="left"
android:visibility="gone"
tools:text="左侧按钮"/>
<LinearLayout
android:id="@+id/layout_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/txt_toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?attr/baseTitleTextColor"
android:textSize="17sp"
tools:text="标题"/>
<TextView
android:id="@+id/txt_toolbar_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:maxLines="1"
android:textColor="#909090"
android:textSize="10sp"
android:visibility="gone"
tools:text="子标题"/>
</LinearLayout>
<ImageButton
android:id="@+id/toolbar_btn_right"
style="@style/AppTheme.ImageButton"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="right"
android:visibility="gone"
tools:text="右侧按钮"/>
</android.support.v7.widget.Toolbar>
<View
android:id="@+id/view_divider"
android:layout_width="match_parent"
android:layout_height="?attr/titleDividerLine"
android:background="?attr/titleDividerColor"/>
</android.support.design.widget.AppBarLayout>
<include layout="@layout/base_content"/>
</android.support.design.widget.CoordinatorLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_main">
<ViewStub
android:id="@+id/content_viewStub"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.yesway.android.view.LoadingView
android:id="@+id/loading_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<com.yesway.android.view.NetworkErrorView
android:id="@+id/network_err"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/img_wheel1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
<TextView
android:id="@+id/txt_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/img_wheel1"
android:layout_centerHorizontal="true"
android:text="努力加载中..."
android:textColor="#888888"
android:textSize="14sp"/>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f0f0f0">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="130dp"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/img_err"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_network" />
<TextView
android:id="@+id/txt_err_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="网络不太给力" />
<TextView
android:id="@+id/txt_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="猛戳屏幕试试手气" />
</LinearLayout>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:background="@drawable/rotate_progress_bg">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@mipmap/rotate_progress_back_bg"
android:layout_centerInParent="true"
/>
<ImageView
android:id="@+id/img_progress"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@mipmap/rotate_progress_front_bg"
android:layout_centerInParent="true"
/>
<TextView
android:id="@+id/txt_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="#565656"
android:textSize="11sp"
/>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="AppTheme.NoActionBar">
<attr name="baseTitleTextColor" format="reference|color" />
<attr name="titleDividerColor" format="reference|color" />
<attr name="titleDividerLine" format="dimension" /> <!-- 是否显示 titlebar 的分割线-->
</declare-styleable>
<declare-styleable name="MagicTextView">
<attr name="innerShadowColor" format="color"/>
<attr name="innerShadowRadius" format="dimension"/>
<attr name="innerShadowDx" format="dimension"/>
<attr name="innerShadowDy" format="dimension"/>
<attr name="outerShadowColor" format="color"/>
<attr name="outerShadowRadius" format="dimension"/>
<attr name="outerShadowDx" format="dimension"/>
<attr name="outerShadowDy" format="dimension"/>
<attr name="typeface" format="string" />
<attr name="foreground" format="reference|color"/>
<attr name="backgroundcolor" format="reference|color"/>
<attr name="strokeWidth" format="dimension" />
<attr name="strokeMiter" format="dimension" />
<attr name="strokeColor" format="color" />
<attr name="strokeJoinStyle">
<enum name="miter" value="0" />
<enum name="bevel" value="1" />
<enum name="round" value="2" />
</attr>
</declare-styleable>
<declare-styleable name="ExpandableTextView">
<attr name="maxCollapsedLines" format="integer"/>
<attr name="animDuration" format="integer"/>
<attr name="animAlphaStart" format="float"/>
<attr name="expandIndicator" format="reference"/>
<attr name="collapseIndicator" format="reference"/>
<attr name="expandToggleType" format="enum">
<enum name="ImageButton" value="0"/>
<enum name="TextView" value="1"/>
</attr>
<attr name="expandableTextId" format="reference"/>
<attr name="expandCollapseToggleId" format="reference"/>
<attr name="expandToggleOnTextClick" format="boolean"/>
</declare-styleable>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="glide_tag" />
<item type="id" name="expandable_text"/>
<item type="id" name="expand_collapse"/>
</resources>
\ No newline at end of file
<resources>
<string name="app_name">lib_common</string>
</resources>
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="titleDividerLine">1dp</item>
<item name="titleDividerColor">@android:color/transparent</item>
</style>
<style name="AppTheme.BackBar" parent="AppTheme.NoActionBar">
<item name="navigationIcon">@drawable/btn_back_menu</item>
<item name="colorPrimaryDark">#2a2a2a</item>
<item name="baseTitleTextColor">#2a2a2a</item>
<item name="colorPrimary">#ff0000</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
<style name="AppTheme.ImageButton">
<item name="android:textColor">#2a2a2a</item>
<item name="android:textSize">14sp</item>
<item name="android:paddingLeft">10dp</item>
<item name="android:paddingRight">10dp</item>
<item name="android:minHeight">0dp</item>
<item name="android:minWidth">0dp</item>
<item name="android:background">@null</item>
</style>
<style name="testToolBar" parent="@style/Widget.AppCompat.Light.PopupMenu.Overflow">
<item name="overlapAnchor">false</item>
</style>
</resources>
package com.fly.tour.common;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}
\ No newline at end of file
...@@ -25,4 +25,13 @@ dependencies { ...@@ -25,4 +25,13 @@ dependencies {
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
//implementation deps.support.multidex
implementation project(':lib_common')
if (!isModule.toBoolean()) {
implementation project(':module_main')
implementation project(':module_find')
implementation project(':module_me')
implementation project(':module_trip')
}
} }
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fly.tour">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:name=".MyApplication"
>
</application>
</manifest>
\ No newline at end of file
package com.fly.tour;
import com.fly.tour.common.BaseApplication;
/**
* Description: <MyApplication><br>
* Author: gxl<br>
* Date: 2018/12/27<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class MyApplication extends BaseApplication {
@Override
public void onCreate() {
super.onCreate();
}
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册