读开源项目《looklook》后总结


看了这个项目的源码之后呢,我在这里列出了大概的知识点,都是大家在平时开发过程中可能碰到的问题。

一.使用场景动画过渡界面

使用Transitions API为安卓应用创建动画
【Transition】Android炫酷的Activity切换效果,共享元素

1.怎样防止去掉状态栏和导航栏因为activity之间的场景动画而产生的动画。

当我们用ActivityOptions.makeSceneTransitionAnimation 使用默认场景启动另外一个activity的时候,我们注意到导航栏和状态栏也会跟着变化。怎么能让它们显示正常呢。

方法一:从Window的exit/enter动画中去除掉状态栏和导航栏。

代码如下:

Transition fade = new Fade();
fade.excludeTarget(android.R.id.statusBarBackground, true);
fade.excludeTarget(android.R.id.navigationBarBackground, true);
getWindow().setExitTransition(fade);
getWindow().setEnterTransition(fade);

当然也可以用xml定义动画:

<?xml version="1.0" encoding="utf-8"?>
<fade xmlns:android="http://schemas.android.com/apk/res/android">
    <targets>
        <target android:excludeId="@android:id/statusBarBackground"/>
        <target android:excludeId="@android:id/navigationBarBackground"/>
    </targets>
</fade>
方法二:将状态栏和导航栏作为共享元素

这个方法是比较常用且有效的,虽然它需要代码的修改比方法一多些。
在将要启动别的activity中加入如下代码:

View statusBar = findViewById(android.R.id.statusBarBackground);
View navigationBar = findViewById(android.R.id.navigationBarBackground);
//如果你用的appcompat支持库,则用   final  View actionBar = decor.findViewById(R.id.action_bar_container);
View actionBar = decor.findViewById(getResources().getIdentifier(
        "action_bar_container", "id", "android"));
 actionBar.setTransitionName("test");
  final List<Pair> participants = new ArrayList<>(4);
  addNonNullViewToTransitionParticipants(statusBar, participants);
addNonNullViewToTransitionParticipants(navigationBar, participants);
addNonNullViewToTransitionParticipants(actionBar, participants);
addNonNullViewToTransitionParticipants(mSharedElement, participants);

Bundle options = ActivityOptions.makeSceneTransitionAnimation(activity, 
        participants.toArray(new Pair[pairs.size()])).toBundle();
startActivity(new Intent(context, NextActivity.class), options);

.....
 private static void addNonNullViewToTransitionParticipants(View view, List<Pair> participants) {
        if (view == null) {
            return;
        }
        participants.add(new Pair<>(view, view.getTransitionName()));
    }

二.Android里那些小知识

1.Fragment的setRetainInstance(true/false)方法

Fragment有一个非常强大的功能——就是可以在Activity重新创建时可以不完全销毁Fragment,以便Fragment可以恢复。最好是在onCreate中调用setRetainInstance(true)方法。调用这个方法以后,当Activity recreate的时候,Fragment的生命周期是不一样的。首先onDestroy()方法是不会被调用的。但是onDetach()方法任然会被调用。因为Fragment被当前的Activity分离开了。同理,当Activity重新创建的时候 onCreate也不会被调用,但是onAttach()和onActivityCreated()任然会被调用。Fragment恢复时会跳过onCreate()和onDestroy()方法,因此不能在onCreate()中放置一些初始化逻辑。

2.SimpleArrayMap和SparseArrays

Android中的HashMap,ArrayMap和SparseArray

3. RecyclerView在21及其以上会抛出IndexOutOfBoundsException问题

解决方法
在LinearLayoutManager中捕获这个异常

public class WrapContentLinearLayoutManager extends LinearLayoutManager {
    @Override
   public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        try {//
            super.onLayoutChildren(recycler, state);
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
        }
    }
}

4. RecyclerView的适配器中通知数据变化方法

 public final void notifyDataSetChanged()
        public final void notifyItemChanged(int position)
        public final void notifyItemRangeChanged(int positionStart, int itemCount)
        public final void notifyItemInserted(int position) 
        public final void notifyItemMoved(int fromPosition, int toPosition)
        public final void notifyItemRangeInserted(int positionStart, int itemCount)
        public final void notifyItemRemoved(int position)
        public final void notifyItemRangeRemoved(int positionStart, int itemCount) 

第一个方法没什么好讲的,跟ListViewAdapter的一样。

  • notifyItemChanged(int position):position数据发生了改变,那调用这个方法,就会回调对应position的onBindViewHolder()方法了,当然,因为ViewHolder是复用的,所以如果position在当前屏幕以外,也就不会回调了,因为没有意义,下次position滚动会当前屏幕以内的时候同样会调用onBindViewHolder()方法刷新数据了。其他的方法也是同样的道理。
  • ** notifyItemRangeChanged(int positionStart, int itemCount):**顾名思义,可以刷新从positionStart开始itemCount数量的item了(这里的刷新指回调onBindViewHolder()方法)。
  • notifyItemInserted(int position):这个方法是在第position位置被插入了一条数据的时候可以使用这个方法刷新,注意这个方法调用后会有插入的动画,这个动画可以使用默认的,也可以自己定义。
  • notifyItemMoved(int fromPosition, int toPosition):这个方法是从fromPosition移动到toPosition为止的时候可以使用这个方法刷新。
  • notifyItemRangeInserted(int positionStart, int itemCount):显然是批量添加。
  • ** notifyItemRemoved(int position):**第position个被删除的时候刷新,同样会有动画。
  • notifyItemRangeRemoved(int positionStart, int itemCount):批量删除。

android5.0中用ConnectivityManager.NetworkCallback监听网络

5. RecyclerView.Adapter使用小技巧

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)中的viewType 可以在public int getItemViewType(int position)中设置,可用来展现多个不同的布局。
示例代码:

 @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        switch (viewType) {
            case NOMAL_ITEM:
                return new TopNewsViewHolder(LayoutInflater.from(mContext).inflate(R.layout.topnews_layout_item, parent, false));

            case TYPE_LOADING_MORE:
                return new LoadingMoreHolder(LayoutInflater.from(mContext).inflate(R.layout.infinite_loading, parent, false));
        }
        return null;
    }
 @Override
    public int getItemViewType(int position) {
        if (position < getDataItemCount()
                && getDataItemCount() > 0) {

            return NOMAL_ITEM;
        }
        return TYPE_LOADING_MORE;
    }

6.RecyclerView实现下拉加载

RecyclerView.OnScrollListener与LinearLayoutManager的结合使用:

 loadingMoreListener = new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                if (dy > 0) //向下滚动
                {
                    int visibleItemCount = mLinearLayoutManager.getChildCount();
                    int totalItemCount = mLinearLayoutManager.getItemCount();
                    int pastVisiblesItems = mLinearLayoutManager.findFirstVisibleItemPosition();

                    if (!loading && (visibleItemCount + pastVisiblesItems) >= totalItemCount) {
                        loading = true;
                        loadMoreDate();
                    }
                }
            }
        };

7.postponeEnterTransition()&startPostponedEnterTransition()

当activity是用ActivityOptions.makeSceneTransitionAnimation(Activity,android.util.Pair[])启动的时候我们可以用postponeEnterTransition()来推迟动画的执行。这个方法可以推迟进入的时间和共享元素动画直到需要的数据都加载完毕。这个可能也会推迟退出动画的执行时间直到数据都加载完毕。这个方法应该在onCreate()或者onActivityReenter方法里面执行。之后在需要动画的地方调用startPostponedEnterTransition()方法来执行动画。如果我们不是用ActivityOptions.makeSceneTransitionAnimation(Activity,android.util.Pair[])来启动的这个Activity,那么postponeEnterTransition()不会做任何事情。

8.android ImageView使用setColorFilter(ColorFilter cf)

调用图片颜色饱和度

9.android 属性动画

Android属性动画Property Animation系列二之ObjectAnimator
用属性动画和ImageView的setColorFilter(ColorFilter cf)写一个小例子:

  final ObservableColorMatrix matrix = new ObservableColorMatrix();
        final ObjectAnimator animator = ObjectAnimator.ofFloat(matrix, ObservableColorMatrix.SATURATION, 0f, 1.0f);
        animator.setDuration(3000);
        //此处运用了策略模式
        animator.setInterpolator(new AccelerateDecelerateInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                ivGuapi.setColorFilter(new ColorMatrixColorFilter(matrix));
            }
        });
       textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                animator.start();

            }
        });
public class ObservableColorMatrix extends ColorMatrix {
    private float saturation = 1f;

    public ObservableColorMatrix() {
        super();
    }

    public float getSaturation() {
        return saturation;
    }

    @Override
    public void setSaturation(float saturation) {
        this.saturation = saturation;
        super.setSaturation(saturation);
    }

    public static final Property<ObservableColorMatrix, Float> SATURATION = new FloatProperty<ObservableColorMatrix>("saturation") {
        @Override
        public void setValue(ObservableColorMatrix observableColorMatrix, float v) {
            observableColorMatrix.setSaturation(v);
        }

        @Override
        public Float get(ObservableColorMatrix observableColorMatrix) {
            return observableColorMatrix.getSaturation();
        }
    };

    public static abstract class FloatProperty<T> extends Property<T, Float> {
        public FloatProperty(String name) {
            super(Float.class, name);
        }

        /**
         * A type-specific override of the {@link #set(Object, Float)} that is faster when dealing
         * with fields of type <code>float</code>.
         */
        public abstract void setValue(T object, float value);

        @Override
        final public void set(T object, Float value) {
            setValue(object, value);
        }
    }

}

效果图如下:


用一下瓜皮的萌照

10.Palette的使用

在Android Lollipop中使用Palette抽取Bitmap颜色

开源支持手势放大缩小图片控件-PhotoView

11.Attr ,style和Theme

Attr、Style和Theme详解

三.Material Design

Android Material Design官方文档
Material Design设计规范
使用 DrawerLayout 实现 Material Design风格的侧滑
Navigation View - Material Design Support Library Tutorial

四.关于Rxjava

给 Android 开发者的 RxJava 详解
这篇入门文章讲得不错。

五. Retrofit与RxJava结合

如果不太了解可以看看Retrofit官网
RxJava 与 Retrofit 结合的最佳实践

六.BufferKnife

这个开源框架可能我们都会用,可是它的实现可能还有人不是很清晰。
ButterKnife源码分析自己去下载一份源码来读读可以学到很多东西的。

七.Glide

Google推荐的图片加载库Glide介绍
Glide源码分析

八.Android MVP架构

浅谈 MVP in Android
Android MVP+Retrofit+RxJava实践小结

如有遗漏,后续会补充。希望对大家有所帮助。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容