嗯嗯,一句代码就搞定 RecycleView 侧滑菜单、添加头部底部、加载更多

很早就萌生了将这种方案封装为一个开源库的想法,旨在实现调用方式最简单,且又不失可定制性。本库最大的特点的是采用了 Glide 简洁明了的链式调用方式,一句代码即可添加侧滑菜单、头部底部等。

特性:

1.自定义侧滑菜单布局 
2.添加头部、底部 
3.轻松实现加载更多 
4.设置 item 间距 
5.多种 item 类型 
6.支持 LinearLayout 及 GridLayout 
7.一句代码实现所有功能

效果:

左侧滑菜单、右侧滑菜单、自定义菜单布局:

    

头部、多头部:

    

底部、多底部、加载更多:

    

集成:

第 1 步、在工程的 build.gradle 中添加:

    allprojects {
        repositories {
            ...
            maven { url ‘https://jitpack.io‘ }
        }
    }

第 2 步、在应用的 build.gradle 中添加:

    dependencies {
            compile ‘com.github.yhaolpz:SlideAdapter:1.0.0‘
    }

使用:

下面通过简单案例演示如何在程序中使用 SlideAdapter,假设 item.xml 为:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:orientation="vertical"
              android:background="#fff"
    >

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:textColor="#000"
        android:textSize="14sp"
        />

</LinearLayout>

数据类为:

public class Bean {

    private String info;

    public Bean(String info) {
        this.info = info;
    }
    // 省略 get、set 方法...
}

数据为:

 final List<Bean> data = new ArrayList<>();
 for (int i = 0; i < 30; i++) {
     data.add(new Bean("我是第" + i + "个item"));
 }

1.基本写法 :

SlideAdapter.load(data)           //加载数据
            .item(R.layout.item)  //指定布局
            .into(recyclerView);  //填充到recyclerView中

2.数据绑定及事件监听:

SlideAdapter.load(data)
            .item(R.layout.item)
            .bind(itemBind)       //视图绑定
            .into(recyclerView);

在 itemBind 中进行数据绑定及控件的事件监听,相当于 Adapter 中的 onBindViewHolder ,实现 ItemBind 时需传入数据类型:

ItemBind itemBind = new ItemBind<Bean>() {
     @Override
     public void onBind(ItemView itemView, Bean data, int position) {
         itemView.setText(R.id.textView, data.getInfo())
                 .setOnClickListener(new View.OnClickListener() {
                     @Override
                     public void onClick(View view) {
                        //点击item
                     }
                  })
                 .setOnClickListener(R.id.textView, new View.OnClickListener() {
                     @Override
                     public void onClick(View view) {
                        //点击textView
                     }
                 });
     }
};

3.添加 item 间距:

SlideAdapter.load(data)
            .item(R.layout.item)
            .padding(2)           //item间距
            .bind(itemBind)
            .into(recyclerView); 

4.添加侧滑菜单:

SlideAdapter.load(data)
            .item(R.layout.item,0,0,R.layout.menu,0.35f)  //添加右侧侧滑菜单,宽为屏幕宽度的 35%
            .padding(2)
            .bind(itemBind)
            .into(recyclerView); 
SlideAdapter.load(data)
            .item(R.layout.item,R.layout.menu,0.4f,0,0)  //添加左侧侧滑菜单,宽为屏幕宽度的 40%
            .padding(2)
            .bind(itemBind)
            .into(recyclerView); 
SlideAdapter.load(data)
            .item(R.layout.item,R.layout.menu,0.4f,R.layout.menu,0.35)  //添加左侧和右侧侧滑菜单
            .padding(2)
            .bind(itemBind)
            .into(recyclerView); 

上面调用的 item 方法为 :

item (int itemLayoutId,
      int leftMenuLayoutId, float leftMenuRatio,
      int rightMenuLayoutId, float rightMenuRatio)

不添加哪一侧,就把对应参数传入 0 即可。

5.侧滑菜单的数据绑定及事件监听:

菜单布局为 itemView 的一部分,所以对侧滑菜单的数据绑定及事件监听直接在 ItemBind 中进行即可。

比如侧滑菜单布局 menu.xml 为下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="#e61313"
              android:gravity="center">
        <ImageView
            android:id="@+id/rightMenu_Like"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@drawable/like"/>
</LinearLayout>

对 rightMenu_Like 控件设置点击事件监听,就像对 item 中的普通控件设置一样:

ItemBind itemBind = new ItemBind<Bean>() {
     @Override
     public void onBind(ItemView itemView, Bean data, int position) {
         itemView.setOnClickListener(R.id.rightMenu_Like, new View.OnClickListener() {
                     @Override
                     public void onClick(View view) {
                        //点击rightMenu_Like
                     }
                 });
     }
};

6.多种 item 布局:

SlideAdapter.load(data)
            .item(R.layout.item,0,0,R.layout.menu,0.35)   // 添加次序为 1
            .item(R.layout.item)                          // 添加次序为 2
            .type(new ItemType<Bean>() {
                 @Override
                 public int getItemOrder(Bean data, int position) {
                      // 返回 item 添加次序
                      return position % 2 == 0 ? 1 : 2;
                 }
             })
            .padding(2)
            .bind(itemBind)
            .into(recyclerView);

7.添加头部:

SlideAdapter.load(data)
            .item(R.layout.item)
            .header(R.layout.head,0.1f) //添加一个头部,高为屏幕高度的 10%
            .padding(2)
            .bind(itemBind)
            .into(recyclerView);
SlideAdapter.load(data)
            .item(R.layout.item)
            .header(R.layout.head)        //添加第1个头部
            .header(R.layout.head2,0.1f)  //添加第2个头部
            .padding(2)
            .bind(itemBind)
            .into(recyclerView);

8.头部的数据绑定及事件监听:

假设头部布局 head.xml 为下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="#fff"
              android:gravity="center"
    >

    <TextView
        android:layout_gravity="center"
        android:id="@+id/headText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="头部"
        android:textColor="#000"
        android:gravity="center"
        />

</LinearLayout>

对头部的数据绑定及事件监听在 HeaderBind 中实现:

SlideAdapter.load(data)
            .item(R.layout.item)
            .header(R.layout.head,0.2f)    //添加第1个头部
            .header(R.layout.head2)        //添加第2个头部
            .bind(new HeaderBind() {
                    @Override
                    public void onBind(ItemView header, int order) {
                        if (order == 1) {
                            header.setText(R.id.headText, "我是第一个头部");
                        }
                        ...
                    }
             })
            .padding(2)
            .bind(itemBind)
            .into(recyclerView);

9.添加底部:

SlideAdapter.load(data)
            .item(R.layout.item)
            .footer(R.layout.foot,0.1f)    //添加一个底部,高为屏幕高度的 10%
            .padding(2)
            .bind(itemBind)
            .into(recyclerView);
SlideAdapter.load(data)
            .item(R.layout.item)
            .footer(R.layout.foot)        //添加第1个底部
            .footer(R.layout.foot,0.1f)   //添加第2个底部
            .padding(2)
            .bind(itemBind)
            .into(recyclerView);

10.底部的数据绑定及事件监听:

假设底部布局 foot.xml 为下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="#fff"
              android:gravity="center"
    >

    <TextView
        android:layout_gravity="center"
        android:id="@+id/footerText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="底部"
        android:textColor="#000"
        android:gravity="center"
        />

</LinearLayout>

对头部的数据绑定及事件监听在 FooterBind 中实现:

SlideAdapter.load(data)
            .item(R.layout.item)
            .footer(R.layout.foot)            //添加第1个底部
            .footer(R.layout.foot,0.1f)       //添加第2个底部
            .bind(new FooterBind() {
                    @Override
                    public void onBind(ItemView footer, int order) {
                        if (order == 2) {
                            footer.setText(R.id.footerText, "我是第2个底部");
                        }
                        ...
                    }
             })
            .padding(2)
            .bind(itemBind)
            .into(recyclerView);

11.加载更多:

SlideAdapter.load(data)
            .item(R.layout.item)
            .footer(R.layout.foot,0.1f)
            .padding(2)
            .bind(itemBind)
            .listen(new BottomListener() {
                    @Override
                    public void onBottom(final ItemView footer, final SlideAdapter slideAdapter) {
                       footer.setText(R.id.footerText, "正在加载,请稍后...");
                       List data2 = getMoreData();
                       slideAdapter.loadMore(data2);
                       footer.setText(R.id.footerText, "加载完成");
                    }
             })
            .into(recyclerView);

onBottom 方法中的 footer 为最后一个底部,若未添加底部,则 footer 为空。其中 SlideAdapter 的 loadMore() 方法专门用来加载更多数据,需在主线程中调用。

实现原理

1.如何实现链式调用

虽然这部分并不难,但毕竟是 SlideAdapter 异于其他库的一大特点,简单介绍一下,直接看代码:

public class SlideAdapter extends RecyclerView.Adapter<ItemView> {

    private static Builder mBuilder = null;
    public static class Builder {
        List data;
        int itemPadding;
        //省略...
        Builder load(List data) {
            this.data = data;
            return this;
        }
        public Builder padding(int itemPadding) {
            this.itemPadding = itemPadding;
            return this;
        }
        //省略...
        public SlideAdapter into(RecyclerView recyclerView) {
            SlideAdapter adapter = new SlideAdapter(mBuilder, recyclerView);
            mBuilder = null;
            return adapter;
        }
    }
    public static Builder load(List data) {
        return getBuilder().load(data);
    }
    private static Builder getBuilder() {
        if (mBuilder == null) {
            mBuilder = new Builder();
        }
        return mBuilder;
    }

}

SlideAdapter 中以 Builder load(List data) 方法为入口,然后进入 Builder 内部链式调用一系列方法,将配置属性暂时记录在 Builder 中,最后通过 SlideAdapter into(RecyclerView recyclerView) 方法将这一系列配置属性传入到 SlideAdapter 的构造函数中使其配置生效。

2.如何实现侧滑菜单

本库基于一种非常简单的侧滑菜单实现方案:

在 item 布局外部添加一层可以滑动的 HorizontalScrollView ,菜单布局也置于其中

也就是说,本库要做的工作是: 自动在 item 布局外部添加一层可以滑动的 HorizontalScrollView 容器。我们要考虑的问题有两个:1.什么时候添加? 2.怎么添加?首先来看第一个问题,答案很简单,当然是在 onCreateViewHolder 中新建 item 布局时添加;怎么添加呢?可以提前写一个布局文件,准备好这层可以滑动的容器,比如:

<?xml version="1.0" encoding="utf-8"?>
<com.wyh.slideAdapter.SlideLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/slideLayout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <LinearLayout
        android:id="@+id/linearLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        />
</com.wyh.slideAdapter.SlideLayout>

其中 SlideLayout 继承自 HorizontalScrollView ,就是这层可以滑动的容器,我们只要把 item 布局塞到 LinearLayout 内部就可以了,怎么塞呢?很简单:

     View itemView = LayoutInflater.from(context).inflate(R.layout.layout, parent, false);//外部容器
     LinearLayout linearLayout = itemView.findViewById(R.id.linearLayout);
     View content = LayoutInflater.from(context).inflate(itemLayoutId, linearLayout, false);//item布局
     linearLayout.addView(content);

这样就成功的把 item 外层裹上可以滑动的 SlideLayout 了,如果要添加侧滑菜单,同理,像 item 布局一样把菜单布局也塞进去就行了,本库是这样实现的:

    if (slideItem.leftMenuLayoutId != 0) {//添加左侧侧滑菜单
        leftMenu = LayoutInflater.from(context).inflate(slideItem.leftMenuLayoutId, linearLayout, false);
        linearLayout.addView(leftMenu);
    }
    content = LayoutInflater.from(context).inflate(slideItem.itemLayoutId, linearLayout, false);
    linearLayout.addView(content);
    if (slideItem.rightMenuLayoutId != 0) {//添加右侧侧滑菜单
        rightMenu = LayoutInflater.from(context).inflate(slideItem.rightMenuLayoutId, linearLayout, false);
        linearLayout.addView(rightMenu);
    }

linearLayout 的 addView 方法是按添加顺序从左到右排列的,所以可以这样实现。其中有一个问题很明显,当没添加侧滑菜单时,仍然给 item 外层添加了 SlideLayout,这的确属于一个漏洞。

最后再说一下 SlideLayout 的实现,其实十分简单,主要就是控制它的滑动,比如当滑开一半多菜单时松手的话,调用其 smoothScrollTo 方法完全打开。

3.如何初始化侧滑菜单

侧滑菜单的初始化包括两部分,一是根据传入的 float 类型数据,初始化侧滑菜单占屏幕宽度的比例,二是初始化侧滑菜单的滑动位置,比如有左侧侧滑菜单时,需要滑动到刚好隐藏掉左侧侧滑菜单的位置。

初始化时机于 onBindViewHolder 中,关键代码如下:

   final SlideItem item = mSlideItems.get(getItemViewType(position) - 1);
   View rightMenu = holder.getRightMenu();
   if (rightMenu != null) {
       LinearLayout.LayoutParams rightMenuParams = (LinearLayout.LayoutParams) rightMenu.getLayoutParams();
       rightMenuParams.width = (int) (ScreenSize.w(holder.itemView.getContext()) * item.rightMenuRatio);
       rightMenu.setLayoutParams(rightMenuParams);
       ((SlideLayout) holder.getView(R.id.yhaolpz_slideLayout)).setRightMenuWidth(rightMenuParams.width);
   }
   View leftMenu = holder.getLeftMenu();
   if (leftMenu != null) {
       LinearLayout.LayoutParams leftMenuParams = (LinearLayout.LayoutParams) leftMenu.getLayoutParams();
       leftMenuParams.width = (int) (ScreenSize.w(holder.itemView.getContext()) * item.leftMenuRatio);
       leftMenu.setLayoutParams(leftMenuParams);
       holder.getView(R.id.yhaolpz_slideLayout).scrollTo(leftMenuParams.width, 0);
       ((SlideLayout) holder.getView(R.id.yhaolpz_slideLayout)).setLeftMenuWidth(leftMenuParams.width);
   }

首先看代码的第 1 行,mSlideItems 中存放了所有类型的 item 的相关数据,包括 item 的 layoutId 、菜单的 layoutId 及其宽度比例。获取到此 postion 对应的 item 类型信息后,再根据宽度比例设置菜单的宽度即可。

怎么初始化 SlideLayout 的滑动位置呢?可以看到程序将侧滑菜单的宽度记录在 SlideLayout 中,有了侧滑菜单的具体宽度,就很容易初始化 SlideLayout 的滑动位置了,重写 SlideLayout 的 onLayout 方法:

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        scrollTo(mLeftMenuWidth, 0);
    }

4.如何兼容 LinearLayout 和 GridLayout

LinearLayout 和 GridLayout 的兼容包括两部分,一是 item 之间的间距,即分割线在 LinearLayout 与 GridLayout 下都能合理分布;二是头部和底部的宽度,若为 GridLayout ,头部底部宽度应该与 RecycleView 宽度一致。

首先来看第一个问题,在 SlideAdapter 构造函数中是这样设置 item 之间间距的:

 if (mItemPadding > 0) {
     mRecycleView.addItemDecoration(new SlideItemDecoration(mItemPadding));
 }

SlideItemDecoration 中重写了 getItemOffsets 方法:

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof LinearLayoutManager) {
            outRect.set(0, 0, 0, mItemPadding);
        }
        if (layoutManager instanceof GridLayoutManager) {
            outRect.set(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
        }
    }

代码很简单,如果是 LinearLayout,就把分割线添加在 item 的下方,如果是 GridLayout ,就把分割线添加在 item 的四周。其实严格来说,这不能叫做分割线,只能叫间距,这种情况下如果要设置“分割线”的颜色,就只能设置 RecycleView 的背景色来实现,当然你也可以添加自己的 ItemDecoration 实现更多分割线效果。

来看第二个问题,如何兼容 item、头部底部的宽度,同样在 SlideAdapter 的构造函数中,把 item 和头部底部的宽度先确定下来:

RecyclerView.LayoutManager layoutManager = mRecycleView.getLayoutManager();
mHeadFootViewWidth = ScreenSize.w(mRecycleView.getContext()) - recyclerViewMargin - recyclerViewPadding;
if (layoutManager instanceof LinearLayoutManager) {
    mItemViewWidth = mHeadFootViewWidth;
}
if (layoutManager instanceof GridLayoutManager) {
    ((GridLayoutManager) layoutManager).setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
        @Override
        public int getSpanSize(int position) {
            return isHeader(getItemViewType(position)) || isFooter(getItemViewType(position)) ?
                    ((GridLayoutManager) layoutManager).getSpanCount() : 1;
        }
    });
   mItemViewWidth = (ScreenSize.w(mRecycleView.getContext()) - recyclerViewMargin - recyclerViewPadding
                    - mItemPadding * ((GridLayoutManager) layoutManager).getSpanCount() * 2) /
                    ((GridLayoutManager) layoutManager).getSpanCount();
   mHeadFootViewWidth -= mItemPadding * 2;
}

代码 2 行把头部底部的宽度确定了下来,值就是 RecycleView 的宽度。如果是 LinearLayout ,item 的宽度就等同于头部底部的宽度;如果是 GridLayout ,item 的宽度就要除以列数并减去 item 间距值。

把 item 、头部底部的宽度值都确定下来以后,在 onBindViewHolder 中直接设置宽度,就成功的实现兼容 LinearLayout 和 GridLayout 了。

5.如何实现多头部、多底部

多头部、多底部无非就是不同的 viewType , SlideAdapter 中规定 item 的 viewType 范围为 1-99 ,头部、底部对应 viewType 的范围为:

    private static final int TYPE_HEADER_ORIGIN = 101; //头部:101~200
    private static final int TYPE_FOOTER_ORIGIN = 201; //底部:201~

相信 100 种 viewType 足够使用了。在 getItemViewType 中确定对应范围:

    @Override
    public int getItemViewType(int position) {
        if (getHeaderNum() > 0 && position < getHeaderNum()) {
            return TYPE_HEADER_ORIGIN + position;
        }
        if (getFooterNum() > 0 && position >= getHeaderNum() + mData.size()) {
            return TYPE_FOOTER_ORIGIN + position - getHeaderNum() - mData.size();
        }
        return mIItemType == null || mSlideItems.size() == 1 ? 1 : mIItemType.type(
                mData.get(position - getHeaderNum()),
                position - getHeaderNum());
    }

其中 getHeaderNum、getFooterNum 方法为下:

    public int getHeaderNum() {
        return mHeaders == null ? 0 : mHeaders.size();
    }

    public int getFooterNum() {
        return mFooters == null ? 0 : mFooters.size();
    }

其中 mHeaders 、mFooters 中分别存储着所有的头部、所有的底部信息,包括 layoutId 和高度比例。确定好 item 、头部及底部的 viewType 后,就可以在 onCreateViewHolder 中根据不同的 viewType 创建不同的 viewHolder 了:

    @Override
    public ItemView onCreateViewHolder(ViewGroup parent, int viewType) {
        if (isHeader(viewType)) {
            return ItemView.create(parent.getContext(), parent, mHeaders.get(viewType - TYPE_HEADER_ORIGIN));
        }
        if (isFooter(viewType)) {
            return ItemView.create(parent.getContext(), parent, mFooters.get(viewType - TYPE_FOOTER_ORIGIN));
        }
        return ItemView.create(parent.getContext(), parent, mSlideItems.get(viewType - 1));
    }

其中的 isHeader、isFooter 方法很简单,根据 viewType 的范围判断即可:

    private boolean isHeader(int viewType) {
        return viewType >= TYPE_HEADER_ORIGIN && viewType < TYPE_FOOTER_ORIGIN;
    }

    private boolean isFooter(int viewType) {
        return viewType >= TYPE_FOOTER_ORIGIN;
    }

ok,在成功创建对应的头部、底部后,还要注意的就是数据的移位,此时 onBindViewHolder 中提供的 position 不能直接用来索引 data 数据,应该减去头部的数量,比如在调用 ItemBind 接口方法时:

  if (mIItemBind != null) {
      mIItemBind.bind(holder, mData.get(position - getHeaderNum()),
              position - getHeaderNum());
  }

实现原理的部分就介绍这么多吧,其实到这里已经把本库的关键点都拿出来剖析说明了,剩下的比如加载更多等功能都比较简单,当然如果你感兴趣的话可以阅读源码,内容并不多,最后附上本库的所有文件:

源码:https://github.com/yhaolpz/SlideAdapter

源码免费下载地址:http://www.jinhusns.com/Products/Download

时间: 2024-10-25 08:31:15

嗯嗯,一句代码就搞定 RecycleView 侧滑菜单、添加头部底部、加载更多的相关文章

一行代码轻松搞定各种IE兼容问题,IE6,IE7,IE8,IE9,IE10

在网站开发中不免因为各种兼容问题苦恼,针对兼容问题,其实IE给出了解决方案Google也给出了解决方案百度也应用了这种方案去解决IE的兼容问题? 百度源代码如下: 1 <!Doctype html> 2 <html xmlns=http://www.w3.org/1999/xhtml xmlns:bd=http://www.baidu.com/2010/xbdml> 3 <head> 4 <meta http-equiv=Content-Type content=

app分享功能,微信分享代码,几行代码轻松搞定

让你的应用支持分享送积分功能,获得更多社交流量. *通过友推,开发者用几行代码就可以为应用添加分享送积分功能,并提供详尽的统计报表 *除了本身具备的分享功能外,开发者也可将积分功能单独集成在已有分享组件的APP上, 让您的应用更多地通过用户的分享推荐触达新用户,获得更多社交流量. 一.分享组件功能 1.支持微信,QQ,新浪微博,QQ空间,短信,邮件等多家大型社交媒体平台一键分享2.支持积分抽奖活动在线活动创建3.后台多维度数据统计用户分享行为以及其他数据,让您及时做出精准的营销定位策略4.集成简

简单代码实现 加载更多效果

JS <script type="text/javascript"> //定义全局变量,用于计算分页 var more_i = 1; $('#showmore').click(function() { $.ajax({ type : 'get', url : '__URL__/ajax_more', data : { 'evalue_id' : {$evalue_info.evalue_id}, 'num' : more_i, }, dataType: 'json', su

vue10行代码实现上拉翻页加载更多数据,纯手写js实现下拉刷新上拉翻页不引用任何第三方插件

vue10行代码实现上拉翻页加载更多数据,纯手写js实现下拉刷新上拉翻页不引用任何第三方插件/库 一提到移动端的下拉刷新上拉翻页,你可能就会想到iScroll插件,没错iScroll是一个高性能,资源占用少,无依赖,多平台的javascript滚动插件.iScroll不仅仅是 滚动.它可以处理任何需要与用户进行移动交互的元素.在你的项目中包含仅仅4kb大小的iScroll,你的项目便拥有了滚动,缩放,平移,无限滚动,视差滚动,旋转功能.iScroll的强大毋庸置疑,本人也非常欢迎大家使用iScr

【制作表情包】Python拆分和合并GIF动态图(几行代码就搞定)

“表情包”是当前社交软件上不可或缺的交流方式,难以用文字表达的意思,发一个“表情包”,对方就能心领神会.下面是小派制作的一个表情包,准确地讲,是在已有表情包的基础上,二次加工而成的. 下面以最简单的代码形式(10行左右),介绍上述“表情包”的制作过程.第一,将GIF动态图拆分成图形帧.下图是网络上找到的一个GIF格式动态图. 利用Python将上述GIF格式动态图拆分图形帧,只需要输入以下代码.其中第1-2行是导入os库.从PIL库中导入Image函数功能.第3行是Image.open打开位于D

几行代码轻松搞定python的sqlite3的存取

很简单: 存数据: 1.加载sqlite3驱动(只需一行代码) 2.用驱动执行查询语句(只需一行代码) 取数据: 1.加载sqlite3驱动(只需一行代码) 2.用驱动执行查询语句(只需一行代码) 乍一看,sqlite存取数据方式似乎都一样,实际上,就是一样,废话不多说 上例子: 1.存以下内容: s=['Alice','Joker','张三','王五'] 2.先建立数据库,再在数据库中建一个数据表: conn=sqlite3.connect('SqliteDatebase.db') #建立数据

搞定! iTunes 不能添加铃声进去

最近换个新铃声,但转换成.m4r 怎么都拖不到铃声里很莫名奇妙,首先确定苹果是允许自己定义铃声的,然后网上查了不少文章,都无济于事所以我想自己记录下自己成功搞定的方法,供各位参考第一步: 把自己想转为铃声的歌拖到 iTunes,选中文件右键点歌曲信息 第二步:在选项中选取40s 以内的时长,确认 第三步:选中新生成的歌曲,转换成 AAC 格式 接下来的这一步许多人都是没注意到的,你会发现之前选中的转成 AAC之后 歌曲时间还是原来那么长,并没有变 这步需要再选中 AAC 格式的重复第三步,这时就

关于监听滚动事件加载更多的代码

$(".rankDetail").scroll(function(){ //rankDetail是大容器的class         var scrollHeight = $(this).scrollTop();         var rankListCount = $(".rankList").length;  //rankList是容器中的一个项目,类似于一个li         var rankListHeight = $(".rankList&q

一句DOS命令搞定文件合并

用Dos的copy命令实现: copy a.js+b.js+c.js abc.js /b 将 a.js b.js c.js 合并为一个 abc.js,最后的 /b 表示文件为二进位文件,copy 命令的其它参数可以在 cmd 里输入 copy /? 学习 在项目存放 JS 的文件夹下新建一个 TXT 文件,将代码复制进去,并修改需要合并哪些文件,最后保存并将 TXT 修改为 BAT 后缀,如下: copy core.js+hros.app.js+hros.appmanage.js+hros.ba