Android杂谈(17)一个开源项目的改动与记录

转载请注意:http://blog.csdn.net/wjzj000/article/details/52650058

本菜GitHub上开源了一个小的Android项目,感兴趣的看官大大们可以star下:

https://github.com/zhiaixinyang/MyFirstApp


这个项目是很久之前下载的,现在已经找不到相关链接...

今天重新再把它梳理一遍,并加以改动。即算是对一些知识点的巩固,也算是完成一次老师布置的作业。

ps:要求让合影,这就算了。影响心情...

首先看一下改动后版本和原项目的对比:

改动后

原版

 

首先项目结构如下,这个一个标准的MVP模式。


项目中包的创建是每个业务创建一个包。其下再通过MVP的模式进行解耦。

通过weather包下的内容来展开MVP模式:


接下来进入代码中逐步分析:

public interface WeatherModel {
    //接口类,具体实现在WeatherModelImpl
    void loadWeatherData(String cityName, WeatherModelImpl.LoadWeatherListener listener);
    void loadLocation(Context context, WeatherModelImpl.LoadLocationListener listener);
}
public class WeatherModelImpl implements WeatherModel {
    private static final String TAG = "WeatherModelImpl";
    //实现WeatherModel,复写相应的方法    @Override
    public void loadWeatherData(String cityName, final LoadWeatherListener listener) {
        try {
            String url = Urls.WEATHER + URLEncoder.encode(cityName, "utf-8");
            //通过OKHttp进行数据请求。
            OkHttpUtils.ResultCallback<String> callback = new OkHttpUtils.ResultCallback<String>() {
                @Override
                public void onSuccess(String response) {
                    List<WeatherBean> lists = WeatherJsonUtils.getWeatherInfo(response);
                    listener.onSuccess(lists);
                }
                @Override
                public void onFailure(Exception e) {
                    listener.onFailure("load weather data failure.", e);
                }
            };
            OkHttpUtils.get(url, callback);
        } catch (UnsupportedEncodingException e) {
            LogUtils.e(TAG, "url encode error.", e);
        }
    }
接下来进入presenter包下:

先看WeatherPresenterImpl中的内容,首先它必然要实现WeatherPresenter接口。值得注意的是他的构造方法。

public WeatherPresenterImpl(Context context, WeatherView weatherView) {
    this.mContext = context;
    this.mWeatherView = weatherView;
    mWeatherModel = new WeatherModelImpl();
}
在这里需要传递一个WeatherView,这也是一个接口,通过名字可以看出它是一个和View有关的接口。没错,其实它就是Activity/Fragment的接口类。

那么在这里,我们可以细想,初始化的时候需要传递Activity/Fragment的接口,那么WeatherPresenterImpl势必要在Activity/Fragment中被初始化,事实也正是如此。当我们打开widget包下的WeatherFragment,我们可以看到:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mWeatherPresenter = new WeatherPresenterImpl(getActivity().getApplication(), this);
}
在onCreate()方法中WeatherPresenterImpl被初始化。

关于MVP的分析就到此为止吧,其实思想比较简单就是抽象的时候需要好好琢磨一番...

以下是所用到的库

compile project(':swipeback')
compile project(':GuillotineMenu_library')//铡刀菜单库
compile project(':cardsUILib')//日常囧图中,卡片视图库
compile 'com.qiushui:blurredview:0.8.1'//动态模糊库
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.jakewharton:butterknife:8.0.1'
apt 'com.jakewharton:butterknife-compiler:8.0.1'
compile 'com.android.support:recyclerview-v7:23.4.0'
compile 'com.google.code.gson:gson:2.7'
compile 'com.android.support:design:23.4.0'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.squareup.okhttp:okhttp:2.7.0'
compile 'org.sufficientlysecure:html-textview:1.3'//超链接TextView库
compile 'com.android.support:cardview-v7:23.4.0'
compile 'com.zgh.collapsiblelistview:collapsiblelistview:1.0.1'//折叠式ListView
接下来谈一谈对铡刀菜单的改造。

首先铡刀菜单是国外一大神写的。效果是挺炫,不过华而不实吧。而且通过源码可以看出,作者主要是为了实现效果。拓展性并不强。使用它主要还是为了学习其中对动画的使用。通过内部封装的一个方法来窥探一下作业的思路。

private ObjectAnimator buildOpeningAnimation() {
    ObjectAnimator rotationAnimator = initAnimator(ObjectAnimator.ofFloat(mGuillotineView, 
            ROTATION, GUILLOTINE_CLOSED_ANGLE, GUILLOTINE_OPENED_ANGLE));
    rotationAnimator.setInterpolator(mInterpolator);
    rotationAnimator.setDuration(mDuration);
    rotationAnimator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
            mGuillotineView.setVisibility(View.VISIBLE);
            isOpening = true;
        }
        @Override
        public void onAnimationEnd(Animator animation) {
            isOpening = false;
            if (mListener != null) {
                mListener.onGuillotineOpened();
            }
        }
        @Override
        public void onAnimationCancel(Animator animation) {
        }
        @Override
        public void onAnimationRepeat(Animator animation) {
        }
    });
    return rotationAnimator;
}

可以看出来他使用的是属性动画,几个变量分别是rotation动画模式,以及旋转角度,并且设置动画的监听。已完成对动画的打开与关闭进行控制。不过我们可以看到这里用到了插值器也就是 Interpolator,被用来修饰动画效果,定义动画的变化率,可以使存在的动画效果accelerated(加速),decelerated(减速),repeated(重复),bounced(弹跳)等。

public class GuillotineInterpolator implements TimeInterpolator {
    public static final float ROTATION_TIME = 0.46667f;
    public static final float FIRST_BOUNCE_TIME = 0.26666f;
    public static final float SECOND_BOUNCE_TIME = 0.26667f;
    public GuillotineInterpolator() {
    }
    public float getInterpolation(float t) {
        if (t < ROTATION_TIME) return rotation(t);
        else if (t < ROTATION_TIME + FIRST_BOUNCE_TIME) return firstBounce(t);
        else return secondBounce(t);
    }
    private float rotation(float t) {
        return 4.592f * t * t;
    }
    private float firstBounce(float t) {
        return 2.5f * t * t - 3f * t + 1.85556f;
    }
    private float secondBounce(float t) {
        return 0.625f * t * t - 1.083f * t + 1.458f;
    }
}

isOpening=true是改造的内容,用于记录此时是打开状态还是关闭状态,方便对动画进行控制。

public void open() {
    if (!isOpening) {
        mOpeningAnimation.start();
    }
}
public void close() {
    if (!isClosing) {
        mClosingAnimation.start();
    }
}

关于铡刀菜单的使用:

guillotineAnimation = new GuillotineAnimation.GuillotineBuilder(guillotineMenu, 
        guillotineMenu.findViewById(R.id.guillotine_hamburger), contentHamburger)
        .setStartDelay(RIPPLE_DURATION)
        .setActionBarViewForAnimation(toolbar)
        .setClosedOnStart(true)
        .build();
从命名可以看出这是Builder设计模式。guillotioneMenu作为铡刀操作的View,contentHamburger是标题栏上的按钮,也就是用于操作铡刀菜单的开与关。

到这就先告一段落吧....


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值