什么是红点更新提示?

红点更新提示类似微信朋友圈有新的朋友消息 时会在“发现”tab上显示红点,表示有新的消息。

目前三种显示方式:

1.显示具体数字

2.只显示红点

3.显示省略,表示数量很多

方案思路:

1.显示红点:通过本地和服务器的时间戳对比,判断是否要显示红点,每个按钮都有其对应的本地时间戳和服务器时间戳。

2.隐藏红点:当红点显示时,点击把红点隐藏。 并判断是否要更新本地时间戳文件。

3.红点时间戳:时间戳需要进行缓存,方式为写入文件。

重点考虑问题:

1.点击按钮后是否要刷新该项的时间戳

2.由于更新时间戳要写入文件 所以尽快能少文件的保存

答:

1.只在按钮为红点显示状态下点击后更新本地时间戳文件。但在接口请求时不马上写入文件。原因如下:

接口请求过程中 -点击了按钮(无法得知该按钮记录的时间是否在服务器里时间的前面还是后面 保存点击时间 另起临时Temp字段 不覆盖当前本地Local时间字段)

              (等请求完后调用回调,再对临时字段的时间进行判断比较)
接口请求成功 -点击了按钮(如果!showing的话,直接返回。如果showing,改变状态,更新时间戳)

2.后台接口参数加入index字段,每次后台有更新服务器时间戳时将index升高,前端请求后对index进行判断,不同则刷新本地时间戳并保存到文件,index相等说明数据库时间戳没有更新,就不处理。

方案说明安排:

方案从后台的字段设计和前端的逻辑处理进行说明,代码所列的顺序为:

后台接口参数--》红点控件(继承ImageView)--》客服端接口类及方法(单例)--》监听类和方法(方法写在接口类中)--》Activity类中的方法

--》工具类Utils的方法(供Activity调用)--》时间戳Model(UserItemUpdateRecord)

接口参数说明

接口:http://X.XX.XX.XXX/api/get_user_item_update_status?
请求方式GET
参数说明:

token=DQR3WF6Q56QW56QW           //用户唯一识别码 可在后台做分组 拓展参数
output
{
    "code":0,//状态码,0代表成功
    "msg":"",//发生错误的原因
    "data":{//具体数据     "index":0,//当前点击记录
        "tip":[//各点时间戳
        {
            "type":"home",
            "date":"2015-09-01",           "count":0,//内容更新数量
        },
        {
            "type":"infomation",
            "date":"2015-11-11",        "count":5,
        },
        {
            "type":"me",
            "date":"2016-01-15",       "count":15,
        }
    ]
}

RedPointImageView

这里红点控件根据数量分成三类,数量判断标准自己定。

public class RedPointImageView extends ImageView {

  //红点长度类型
    private static final int TYPE_ZERO = 0;
    private static final int TYPE_SHORT = 1;
    private static final int TYPE_LONG = 2;

    private int type;

  //保存onSizeChange()里的宽高
    private int width;
    private int height;

  //按钮Tag,用来识别
    private String mTag;
    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Rect mRect = new Rect();
    private RelativeLayout mRlPoint = null;
    private Drawable mDPoint = null;
    private int radius;
    private boolean mShow = false;
    private int number;
    private TextView mTvPoint;

    public RedPointImageView(Context context) {
        super(context);
        this.number = -1;
        init();
    }

    public RedPointImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.number = -1;
        init();
    }

    public RedPointImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.number = -1;
        init();
    }

    private void init() {
        if(number<0)return;  //数量小于0直接返回
        mPaint.setFilterBitmap(true);
        radius = getResources().getDimensionPixelSize(R.dimen.red_point_radius);

        mRlPoint = new RelativeLayout(getContext());

        mTvPoint = new TextView(getContext());

        mTvPoint.setTextSize(14);
        mTvPoint.setTextColor(getResources().getColor(R.color.white));
        RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        params1.setMargins(0,0,0,0);
        params1.addRule(RelativeLayout.CENTER_IN_PARENT);
        mRlPoint.addView(mTvPoint,params1);
        initUI();
    }

  
    private void initUI(){
        if(number == 0){          //ZERO类型  
            mTvPoint.setText("");
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(getResources().getDimensionPixelOffset(R.dimen.margin_8),getResources().getDimensionPixelOffset(R.dimen.margin_8));
            params.setMargins(0,0,0,0);
            mRlPoint.setLayoutParams(params);
            mRlPoint.setBackgroundResource(R.drawable.icon_red_point);
            type = TYPE_ZERO;

        }else if(number>0&&number<10){  //SHORT类型
            mTvPoint.setText(String.valueOf(number));
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(getResources().getDimensionPixelOffset(R.dimen.margin_15),getResources().getDimensionPixelOffset(R.dimen.margin_15));
            params.setMargins(0,0,0,0);
            mRlPoint.setLayoutParams(params);
            mRlPoint.setBackgroundResource(R.drawable.icon_red_point);
            type = TYPE_SHORT;
        }else{                //LONG类型
            mTvPoint.setText("···");
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(getResources().getDimensionPixelOffset(R.dimen.margin_20),getResources().getDimensionPixelOffset(R.dimen.margin_12));
            params.setMargins(0,0,0,0);
            mRlPoint.setLayoutParams(params);
            mRlPoint.setBackgroundResource(R.drawable.bg_corner_red);
            type = TYPE_LONG;
        }
        mDPoint = new BitmapDrawable(null,convertViewToBitmap(mRlPoint));
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = w;
        height = h;
        updateRect(w, h);
    }

    private void updateRect(int w, int h) {
        int left,top,right,bottom;
        if(type == TYPE_SHORT){
            left = w - radius;
            top = 0;
            right = w;
            bottom = radius;
        }else if(type == TYPE_ZERO){
            left = w - radius*2/3;
            top = 0;
            right = w;
            bottom = radius*2/3;
        }else{
            left = w - radius/3*4;
            top = 0;
            right = w;
            bottom = radius/5*4;
        }

        mRect.set(left, top, right, bottom);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mShow) {
            drawRedPoint(canvas);
        }
     }

    private void drawRedPoint(Canvas canvas) {
        if (mDPoint == null) {
            return;
        }

        canvas.save();
//        canvas.clipRect(mRect, Region.Op.DIFFERENCE);

        mDPoint.setBounds(mRect);
        mDPoint.draw(canvas);

        canvas.restore();
    }

    public void setShow(boolean isShow){
        this.mShow = isShow;
        invalidate();
    }

    public boolean isShow(){
        return mShow;
    }

    public String getmTag() {
        return mTag;
    }

    public void setmTag(String mTag) {
        this.mTag = mTag;
    }

    public void updateItem(){
        UserItemUpdateRecord userItemUpdateRecord = IpinClient.getInstance().getAccountManager().getUserItemUpdateRecord();
        if(userItemUpdateRecord!=null){
            userItemUpdateRecord.refreshUpdateImg(this);
        }
    }

    public void setNumber(int number){
        this.number = number;
        if(number<0) mShow = false;
        else mShow = true;
        init();
        onSizeChanged(width,height,width,height);
        invalidate();
    }

    public static Bitmap convertViewToBitmap(View view){
        view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
        view.buildDrawingCache();
        Bitmap bitmap = view.getDrawingCache();

        return bitmap;
    }

}

接口类方法

1.tryToLoadUserItemStatus() --> 从本地文件里读取红点时间戳对象

2.requestUserItemStatus() --> 接口请求服务器端的红点时间戳

3.saveItemUpdateStatusToFile() --> 保存红点时间戳到本地文件

    public static final String URL_GET_USER_ITEM_STATUS = "http://m.gaokao.ipin.com/api/get_user_item_update_status?";//获取用户按钮更新信息

    public static final String FILE_NAME_USER_ITEM_STATUS = "user_item_status.ipin";//按钮更新状态文件

    private AtomicBoolean isLoadedUserItemStatus = new AtomicBoolean(false);

    private HashSet<OnUpdateItemStatusListener> mOnUpdateItemStatusListeners = new HashSet<>();//监听列表

    private UserItemUpdateRecord userItemUpdateRecord;//时间戳model
    private boolean isRequestingUserItemStatus = false;//是否正在获取数据

    /**
     * 从文件中读取按钮更新信息
     */
    private void tryToLoadUserItemStatus(){

        TaskExecutor.getInstance().post(new Runnable() {
            @Override
            public void run() {
                synchronized (AccountManager.class) {

                    boolean b = checkAndCopyUserData(AccountConstant.FILE_NAME_USER_ITEM_STATUS);
                    if (!b) {
                        isLoadedUserItemStatus.set(true);
            requestUserItemStatus();
                        return;
                    }
                    String path = StorageManager.getInstance().getPackageFiles() + AccountConstant.FILE_NAME_USER_ITEM_STATUS;
                    Object object = FileUtil.readObjectFromPath(path);

                    if (object != null && object instanceof UserItemUpdateRecord) {
                        userItemUpdateRecord = (UserItemUpdateRecord) object;
                    }

                    isLoadedUserItemStatus.set(true);
            requestUserItemStatus();
                }
            }
        });
    }

    private boolean checkAndCopyUserData(String path) {
      String newPath = StorageManager.getInstance().getPackageFiles() + path;

      String oldPath = StorageManager.getInstance().getPackageCacheRoot() + path;
      File newFile = new File(newPath);
      if (newFile.exists()) {
        return true;
      }

      File oldFile = new File(oldPath);
      if (!oldFile.exists()) {
        return false;
      }

      return oldFile.renameTo(newFile);
    }

/**
     * 请求服务器更新按钮的时间戳
     */
    public void requestUserItemStatus(){

        isRequestingUserItemStatus = true;
        final IRequest request = (IRequest) IpinClient.getInstance().getService(IpinClient.SERVICE_HTTP_REQUEST);
        if (request == null) {
            return;
        }
        request.sendRequestForPostWithJson(AccountConstant.URL_GET_USER_ITEM_STATUS, getParamForGetUserInfo(getIpinToken()), new IRequestCallback() {
            @Override
            public void onResponseSuccess(JSONObject jsonObject) {

                if (jsonObject == null) {
                    return;
                }

                if(jsonObject.getInteger(Constant.KEY_CODE)!=0)return;
                if(jsonObject.getJSONObject(Constant.KEY_DATA)==null)return;

                jsonObject = jsonObject.getJSONObject(Constant.KEY_DATA);
                if(userItemUpdateRecord!=null&&userItemUpdateRecord.getIndex() == jsonObject.getInteger("index"))            return;//如果服务器的index与本地的一样,则目前已经保存最新的更新时间戳,不执行更新本地时间戳操作

                UserItemUpdateRecord updateRecord = new UserItemUpdateRecord();
                updateRecord.decode(jsonObject);
                userItemUpdateRecord = updateRecord;
                isRequestingUserItemStatus = false;
                dispatchOnUpdateItemStatusListener();
                TaskExecutor.getInstance().post(new Runnable() {
                    @Override
                    public void run() {
                        saveItemUpdateStatusToFile();//将时间戳保存至文件
                    }
                });

            }

            @Override
            public void onResponseSuccess(String str) {
        isRequestingUserItemStatus = false;
            }

            @Override
            public void onResponseError(int code) {
        isRequestingUserItemStatus = false;
            }
        });
    }

    /**
     *  保存用户按钮更新信息
     */
    private void saveItemUpdateStatusToFile() {

        TaskExecutor.getInstance().post(new Runnable() {
            @Override
            public void run() {
                if (userItemUpdateRecord != null) {
                    String path = StorageManager.getInstance().getPackageFiles() + AccountConstant.FILE_NAME_USER_ITEM_STATUS;//path为文件路径
                    FileUtil.writeObjectToPath(userItemUpdateRecord, path);
                }

            }
        });
    }

接口请求完的服务器时间戳需要保存到文件里,并更新本地model

监听类及方法

    public interface OnUpdateItemStatusListener {
        void updateItemStatus();
    }

    private HashSet<OnUpdateItemStatusListener> mOnUpdateItemStatusListeners = new HashSet<>();

    public void registerOnUpdateItemStatusListener(OnUpdateItemStatusListener listener) {
        mOnUpdateItemStatusListeners.add(listener);
    }

    public void unregisterOnUpdateItemStatusListener(OnUpdateItemStatusListener listener) {
        mOnUpdateItemStatusListeners.remove(listener);
    }

    private void dispatchOnUpdateItemStatusListener() {
        for (OnUpdateItemStatusListener listener : mOnUpdateItemStatusListeners) {
            listener.updateItemStatus();
        }
    }

使用红点的类中的方法

  private RedPointImageView mButton1;
  private RedPointImageView mButton2;
  private RedPointImageView mButton3;
  mButton1.setmTag(UserItemUpdateRecord.KEY_HOME);//给按钮设置备注,可做判断识别  mButton2.setmTag(UserItemUpdateRecord.KEY_INFORMATION);  mButton3.setmTag(UserItemUpdateRecord.KEY_ME);
  MyClient.getInstance().getAccountManager().registerOnUpdateItemStatusListener(this);//注册监听

    @Override
    public void updateItemStatus() {//监听回调方法
        checkAndUpdateItemStatus();
    }

    private void checkAndUpdateItemStatus(){
        List<RedPointImageView> views = new ArrayList<>();
        views.add(mButton1);
        views.add(mButton2);
        views.add(mButton3);
        MyUtils.updateRedPointItem(getActivity(),views);//调用工具类中的方法
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        IpinClient.getInstance().getAccountManager().unregisterOnUpdateItemStatusListener(this);//注销监听
    }

    //点击时按钮调用方法
    mButton.updateItem();

工具类MyUtils中的方法

    /**
    * 检查更新按钮红点状态
    * @param imageView
    */
    public static void updateRedPointItem(List<RedPointImageView> imageView){
        for (RedPointImageView view : imageView){
            updateRedPointItem(view);
        }
    }

    public static void updateRedPointItem(RedPointImageView imageView){
        UserItemUpdateRecord userItemUpdateRecord = IpinClient.getInstance().getAccountManager().getUserItemUpdateRecord();
        if(userItemUpdateRecord.isNeedUpdate(imageView)){
            imageView.setShow(true);
        }
    }

UserItemUpdateRecord类

    public class UserItemUpdateRecord  implements Serializable, IParse {

            private static final String KEY_INDEX = "index";

            //这里拿了三个按钮作为例子,每一个按钮需要配置一个字符串(Json转换)和
            //三个参数(服务器时间戳mDSystemXX、移动端时间戳mDXX、移动端临时时间戳mDTempXX,这个临时时间戳的作用前面已经说明)
            public static final String KEY_HOME = "home";
            public static final String KEY_INFORMATION = "information";
            public static final String KEY_ME = "me";

            private int index;

            private Date mDHome;
            private Date mDTempHome;
            private Date mDSystemHome;
            private Date mDInformation;
            private Date mDTempInformation;
            private Date mDSystemInformation;
            private Date mDMe;
            private Date mDTempMe;
            private Date mDSystemMe;

            public UserItemUpdateRecord() {
                mDTempHome = getDateForTemp("2015-01-01 01:01:01");
                mDTempInformation = getDateForTemp("2015-01-01 01:01:01");
                mDTempMe = getDateForTemp("2015-01-01 01:01:01");
                mDHome = new Date();
                mDTempHome = new Date();
                mDSystemHome = new Date();
            }

            public void decode(JSONObject object){
            if(index == object.getInteger(KEY_INDEX))return;
            index = object.getInteger(KEY_INDEX);
            mDSystemHome = object.getDate(KEY_HOME);
            mDSystemInformation = object.getDate(KEY_INFORMATION);
            mDSystemMe = object.getDate(KEY_ME);

            if(mDHome==null)mDHome = mDSystemHome;
            if(mDInformation==null)mDInformation = mDSystemInformation;
            if(mDMe==null)mDMe = mDSystemMe;
            }

            @Override
            public JSONObject encode(Object o) {
                return null;
            }

            @Override
            public void release() {

            }

            /**
             * 判断是否需要显示红点
             * @param imageView
             * @return
             */
            public boolean isNeedUpdate(RedPointImageView imageView){
                    String tag = imageView.getmTag();
                    switch (tag){
                    case KEY_HOME:
                        return judgeIsNeedUpdate(imageView,mDHome,mDTempHome,mDSystemHome);
                    case KEY_INFORMATION:
                        return judgeIsNeedUpdate(imageView,mDInformation,mDTempInformation,mDSystemInformation);
                    case KEY_ME:
                        return judgeIsNeedUpdate(imageView,mDMe,mDTempMe,mDSystemMe);
                    default:
                        return false;
                   }

                }

            /**
             * 只有当mDSystem在mDLocal、mDTemp之后才需要显示
             * @param mDLocal 本地点击时间
             * @param mDTemp  点击最新时间
             * @param mDSystem 系统更新时间
             * @return
             */
            private boolean judgeIsNeedUpdate(RedPointImageView view,Date mDLocal ,Date mDTemp,Date mDSystem){
                if(mDLocal.before(mDSystem)){
                        if(mDTemp==null)mDTemp = new Date(mDLocal.getTime());
                        if(mDSystem.before(mDTemp)){    //判断方法加入刷新动作 这里处理了前面说到的接口请求过程中点击按钮,把时间保存在临时Temp参数,这里进行判断并处理,可减少写入文件次数。
                            mDLocal.setTime(mDTemp.getTime());
                            executeUpdate(view,mDInformation,mDTempInformation);
                            //刷新
                            return false;
                        }else{
                            return true;
                        }

                }else{
                        return false;
                }

            }

            /**
             * 点击时触发的处理方法
             * @param view
             */
            public void refreshUpdateImg(RedPointImageView view){
                String tag = view.getmTag();
                switch (tag){
                    case KEY_HOME:
                        executeUpdate(view,mDHome,mDTempHome);
                        break;
                    case KEY_INFORMATION:
                        executeUpdate(view,mDInformation,mDTempInformation);
                        break;
                    case KEY_ME:
                        executeUpdate(view,mDMe,mDTempMe);
                        break;
                }
            }

            private void executeUpdate(RedPointImageView view,Date mDLocal ,Date mDTemp){
                boolean flag = IpinClient.getInstance().getAccountManager().isRequestingUserItemStatus();
                if(flag){
                        mDTemp.setTime(new Date().getTime());//只更新Temp时间,等待接口请求完刷新状态的时候做是否要保存点击时间的判断
                        if(view.isShow()){
                            view.setShow(false);
                        }
                }else{
                        if(view.isShow()){ //接口已经请求完 并且处于红点显示状态,使红点不显示,并且保存当前点击时间
                            mDLocal.setTime(new Date().getTime());
                            IpinClient.getInstance().getAccountManager().saveItemUpdateStatusToFile();
                            view.setShow(false);
                        }else{
                            //接口已经请求完 并且处于红点不显示状态,不做时间保存处理
                        }
                }
            }

            private Date getDateForTemp(String time){
                Date date = new Date();
                SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                try {
                        date = df.parse(time);
                } catch (ParseException e) {
                        e.printStackTrace();
                }
                return date;
            }

            public int getIndex() {
                return index;
            }

            public void setIndex(int index) {
                this.index = index;
            }

            public Date getmDHome() {
                return mDHome;
            }

            public void setmDHome(Date mDHome) {
                this.mDHome = mDHome;
            }

            public Date getmDInformation() {
                return mDInformation;
            }

            public void setmDInformation(Date mDInformation) {
                this.mDInformation = mDInformation;
            }

            public Date getmDMe() {
                return mDMe;
            }

            public void setmDMe(Date mDMe) {
                this.mDMe = mDMe;
            }

            public Date getmDSystemMe() {
                return mDSystemMe;
            }

            public void setmDSystemMe(Date mDSystemMe) {
                this.mDSystemMe = mDSystemMe;
            }

            public Date getmDSystemHome() {
                return mDSystemHome;
            }

            public void setmDSystemHome(Date mDSystemHome) {
                this.mDSystemHome = mDSystemHome;
            }

            public Date getmDSystemInformation() {
                return mDSystemInformation;
            }

            public void setmDSystemInformation(Date mDSystemInformation) {
                this.mDSystemInformation = mDSystemInformation;
            }
    }

Android应用中-更新提示显示红点的方案的更多相关文章

  1. Android Studio中设置提示函数用法

    Eclipse有一个很好的功能,就是当你代码调用某个android API时,鼠标移到对应的函数或者方法上,就会自动有一个悬浮窗提示该函数的说明(所包含的参数含义,该方法功能).迁移到Android ...

  2. Android: Service中创建窗口显示

    WindowManager.LayoutParams: int TYPE_SYSTEM_ALERT  Window type: system window, such as low power ale ...

  3. Android studio无法更新 提示网络连接失败

    Android studio 更新时,提示网络问题 “Connection failed. Please check your network connection and try again” 在默 ...

  4. 如何控制android系统中NavigationBar 的显示与隐藏

    我们使用的大多数android手机上的Home键,返回键以及menu键都是实体触摸感应按键.如果你用Google的Nexus4或Nexus5话,你会发现它们并没有实体按键或触摸感应按键,取而代之的是在 ...

  5. eclipse,代码中有错误,项目或者java类中却不显示红叉

    修改eclipse代码提示级别1.单个项目修改项目上右键-->properties-->java compiler-->building-->enable project sp ...

  6. Eclipse,代码中有错误,项目中却不显示红叉

    ***修改eclipse 代码提示级别1.单个项目修改项目上右键-->properties-->java compiler-->building-->enable projec ...

  7. ionic ng-src 在网页显示,但是导出apk在android手机中运行不显示图片

    解决方法参照: http://stackoverflow.com/questions/29896158/load-image-using-ng-src-in-android-ionic-aplicat ...

  8. Android studio设置参数提示

    在Android studio的使用的过程中,那么就需要对当前的代码显示当前的方式做一个的提示信息,那么可以通过Android studio的的设置的方法,来对Android studio方法的提示显 ...

  9. 在 Android开发中,性能优化策略十分重要

    在 Android开发中,性能优化策略十分重要本文主要讲解性能优化中的布局优化,希望你们会喜欢.目录 示意图 1. 影响的性能 布局性能的好坏 主要影响 :Android应用中的页面显示速度 2. 如 ...

随机推荐

  1. 分享一个与ABP配套使用的代码生成器源码

    点这里进入ABP系列文章总目录 分享一个与ABP配套使用的代码生成器源码 真对不起关注我博客的朋友, 因最近工作很忙, 很久没有更新博客了.以前答应把自用的代码生成器源码共享出来, 也一直没有时间整理 ...

  2. [No000090]C#捕获控制台(console)关闭事件及响应cmd快捷键

    捕获控制台(console)关闭事件: 1.Ctrl+C信号: 2.Ctrl+Break信号: 3.用户系统关闭Console时: 4.用户退出系统时: 5.系统将要关闭时: using System ...

  3. Java范型随笔

    最近在帝都好无聊啊, 排遣寂寞就只有让自己不要停下来,不断的思考了 QWQ; 最近做ndk, java有点忘了,突然看到了一些java范型方面的问题, 踌躇了一会, 想着想着,决定还是写个随笔记录下来 ...

  4. [VS2013]如何闪开安装VS2013必须要有安装IE10的限制

    来源:http://blog.163.com/qimo601@126/blog/static/1582209320143354446462/   已阻止安装程序,此版本的Visual Studio需要 ...

  5. 两分钟了解REACTIVEX

    可能在之前,你就已经看过这篇响应式编程的入门.什么?太长?好吧,这都没关系,Rx并不难,你甚至可以自己实现一个这样的框架. 知道数组吧?你当然知道,这就是: [ 14, 9, 5, 2, 10, 13 ...

  6. angular4 ionic3 app

    对于angular系列来说,从2到4仅仅是版本号的变更,绝大部分都是兼容的.  如果按照规范编写代码,一般来说是没有问题的. 学习angular4     快速入门参考  https://www.an ...

  7. FlappyBirdWeb素材资源

    https://pan.baidu.com/s/1UeNmhnmK4RInmfiEduPrAQ 先上网盘地址 https://github.com/JIANGYUJING1995/FlappyBird ...

  8. 值得收藏:一份非常完整的 MySQL 规范

    一.数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割. 所有数据库对象名称禁止使用 MySQL 保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来). 数据库对象的命名要能 ...

  9. Java中substring函数的简单应用

    1.删掉一个字符串中的某个字符 /* * 使用Java 中的 substring()函数删掉字符串中的某个字符 * deleteAssignChar函数的参数说明: * str:被操作的字符串 * o ...

  10. 吴裕雄 python深度学习与实践(6)

    from pylab import * import pandas as pd import matplotlib.pyplot as plot import numpy as np filePath ...