首页 > 代码库 > 轮播图片的状态栏沉浸

轮播图片的状态栏沉浸

1. 效果

最近碰到这种类似需求,然后做出如图所示的效果。
技术分享
技术分享
源代码地址:github ,如果对你有帮助希望给个star。

2. 干货

  1. 给RecyclerView添加header,这里我使用的是这位大佬的库,添加header ,内容有点多, 但是我们如果要用,就是其中一部分就可以了,等下见代码。
  2. 当图片在顶部时,会将图片沉浸到状态栏,用到这位大佬的库,沉浸状态栏工具 ,封装的很好,原理也说的很清楚,也不大,其实将网上的沉浸状态栏方法进行了总结。
  3. 使图片轮播的一个类,ScheduledExecutorService,他可以定时周期执行指定任务.
    a.布局代码很简单,就是个recyclerview,见代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">


    </android.support.v7.widget.RecyclerView>

</LinearLayout>

b. 然后获取数据,包括两部分,一个是图片资源数据,我这里是将图片资源放在项目中了,真正项目中,应该不是,会做成接口,但是这里就这样做吧,将资源id放在一个数组中。还有就是列表数据,这里我直接是一个string集合,见代码。

 private void initDatas() {

        imgResIds = new int[]{R.mipmap.a1,R.mipmap.a2,R.mipmap.a3};

        for(int i=0;i<40;i++){

            stringLists.add("德德德玛西亚~~"+i);

        }

    }

c.然后我们在setContent()后面调用设置状态的方法

StatusBarUtil.setTranslucentForImageView(MainActivity.this,0,null);

进入这个方法,我们可以看到这样一段代码

     /**
     * 为头部是 ImageView 的界面设置状态栏透明
     *
     * @param activity       需要设置的activity
     * @param statusBarAlpha 状态栏透明度
     * @param needOffsetView 需要向下偏移的 View
     */
    public static void setTranslucentForImageView(Activity activity, int statusBarAlpha, View needOffsetView) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
            return;
        }
        setTransparentForWindow(activity);
        addTranslucentView(activity, statusBarAlpha);
        if (needOffsetView != null) {
            ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) needOffsetView.getLayoutParams();
            layoutParams.setMargins(layoutParams.leftMargin, layoutParams.topMargin + getStatusBarHeight(activity),
                layoutParams.rightMargin, layoutParams.bottomMargin);
        }
    }

经过查资料可知这段代码的意思,设置状态栏是4.4才出来的新东西,所以在4.4以前,谁都不能用什么方法都不可以设置,所以小于4.4时return,进入setTransparentForWindow(),可以看到如下的代码

  /**
     * 设置透明
     */
    private static void setTransparentForWindow(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
            activity.getWindow()
                .getDecorView()
                .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            activity.getWindow()
                .setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        }
    }

集中当5.0以上后,设置状态栏透明很简单,直接这样代码
activity.getWindow().setStatusBarColor(Color.TRANSPARENT);就可以,其中下面这行代码是为了处理状态栏和activity之间的关系,差不多包含activity覆盖状态栏,不会覆盖,共存。

activity.getWindow()
.getDecorView()
.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

不清楚的可以看这里,点击
所以上面这些所以方法就是为了让状态栏透明,然后他为了满足不同的需求,还兼容设置状态栏的透明度,就是这行代码

addTranslucentView(activity, statusBarAlpha);

还有第三个参数那个view我使用了下,一般我们图片沉浸会和toolbar配合使用,这里theme是noactionbar,但是在FrameLayout中加了toolbar后,这个横条会直接顶到状态栏去,所以这明显是不行的,所以设置下移,但是我这里没有设置view,所以这里可以直接null。
d. 对recyclerview初始化,因为为了体验,我这里将轮播的图片添加到recyclerview的头部去,因为如果不这样,会出现这样的情况,上面图片在轮播固定死,而列表的滑动在屏幕的中间滑动,效果很差。代码如下:

 private void initRecyView() {

        recyclerView = (RecyclerView) this.findViewById(R.id.recyView);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        /**
         * 使用了框架,设置itemdecoration
         * */
        recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(this)
                .color(Color.LTGRAY)
                .sizeResId(R.dimen.divider)
                .marginResId(R.dimen.leftmargin, R.dimen.rightmargin)
                .build());

        adapter = new CommonAdapter<String>(this,stringLists,R.layout.item) {
           @Override
           public void convert(ViewHolder holder, String s) {
               holder.setText(R.id.tv, s);
           }
       };

        adapter.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(ViewGroup parent, View view, Object o, int position) {

                Toast.makeText(MainActivity.this,"你是几-->"+position,Toast.LENGTH_SHORT).show();

            }

            @Override
            public boolean onItemLongClick(ViewGroup parent, View view, Object o, int position) {
                return false;
            }
        });
       initHeaderAndFooter();

    }

上面代码是recyclerview的内容不是这里的重点,添加头部的方法就是这里 initHeaderAndFooter();代码如下:

    private void initHeaderAndFooter()
    {
        mHeaderAdapter = new HeaderRecyclerAndFooterWrapperAdapter(adapter) {
            @Override
            protected void onBindHeaderHolder(ViewHolder viewHolder, int headerPos, int layoutId, Object o) {

                switch (layoutId){

                    case R.layout.header1:

                        HeaderView1 header1 = (HeaderView1) o;
                        viewHolder.setImageResource(R.id.iv,header1.getImgResId());
                        break;

                }

            }
        };



        //因为这里只有一个头部,所以使用的方法是add,如果多个,则要使用set
        mHeaderAdapter.addHeaderView(R.layout.header1,getHeader1Obj());

        recyclerView.setAdapter(mHeaderAdapter);


    }

其中layout.header1的布局就是一张图片,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="240dp"
        android:scaleType="fitXY"
        android:src="@mipmap/a1"/>


</FrameLayout>

对象HeaderView1就是一个资源di

package guozhaohui.com.sliderstatusbar;

/**
 * Created by ${GuoZhaoHui} on 2017/2/7.
 * Abstract:
 */

public class HeaderView1 {

    private int imgResId;

    public HeaderView1(int imgResId) {
        this.imgResId = imgResId;
    }

    public int getImgResId() {
        return imgResId;
    }

    public void setImgResId(int imgResId) {
        this.imgResId = imgResId;
    }
}

在这里差不多可以是图片沉浸了,但是为了让图片轮播,还要处理这个
ScheduledExecutorService,代码如下:

   setContentView(R.layout.activity_main);

        StatusBarUtil.setTranslucentForImageView(MainActivity.this,0,null);

        initDatas();

        this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
        this.scheduledExecutorService.scheduleWithFixedDelay(new ViewPagerTask(), 2, 2, TimeUnit.SECONDS);

        initRecyView();

我这里让它在没张图片停留两秒,然后没隔两秒做的任务是将头部header内容清空,然后在添加头部,这样就实现了轮播了。代码如下:

  public class ViewPagerTask implements Runnable{

        @Override
        public void run() {
            currentPageImg = (currentPageImg+1) % imgResIds.length;
            //更新界面
            handler.obtainMessage().sendToTarget();
        }

    }
    private Handler handler = new Handler(){
        public void handleMessage(android.os.Message msg) {


            mHeaderAdapter.clearHeaderView();//这里要将header清除,不然会叠加
            mHeaderAdapter.addHeaderView(R.layout.header1,getHeader1Obj());
            mHeaderAdapter.notifyDataSetChanged();

       //注意不能在这里调用这个方法,因为每次调用这个方法都会将整个adapter刷新,并不能保存当前的状态,可以自行验证,当下滑后,会出现bug
//            recyclerView.setAdapter(mHeaderAdapter);

        };
    };

3. 道友留步

源码位置如果帮到你给个star,,,

<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    轮播图片的状态栏沉浸