您的位置:首页 > 移动开发 > Android开发

【RecyclerView】Android 横竖屏切换 超便捷解决方案

2015-09-25 10:28 627 查看
相信Android 开发者大多数都遇到过横竖屏切换的需求,往往最后选择了锁定竖屏,或者锁定横屏的体验。或者每次切换屏幕就要切换显示数据的控件。谷歌官方推出的RecyclerView控件让你不再有这样的烦恼。

最近这两天又不是很忙了,闲下来看了些关于5.0的一些特性,比如材料设计规范、阴影、主题等等,还有RecyclerView和CardView这两个不错的控件。看到RecyclerView的时候感觉眼前一亮,毫无疑问,它能够完全胜任ListView,GridView以及现在流行的瀑布流(交错布局)显示,并且有着高度解耦,高自由度(自定义分隔线,自定义载入/删除动画等)等特点。

在这里,我用它写了一个横竖屏切换便捷解决方案的Demo。

本demo于API 23 + eclipse环境中完成(但本demo兼容低版本,如下载demo可以修改最低版本)

1.获取RecyclerView的jar包

RecyclerView虽然是谷歌官方推出的控件,但是为了兼容5.0以前的系统版本,它是属于V7兼容包下独立打包的。所以如果我们要使用RecyclerView的话需要导入这个jar包。

更新SDK Manager 中Extras的support library到21+版本后,其jar包在如下位置:

sdk\extras\android\support\v7\recyclerview\libs\android-support-v7-recyclerview.jar

如果不方便更新sdk的话,点击jar包下载地址

导入项目并add to build path。

2.Activity中横竖屏切换控制

OrientationChangeActivity.java

/**
 * @author 尘笑ys
 *  RecyclerView 横竖屏切换demo
 */
public class OrientationChangeActivity extends Activity {

    private RecyclerView recyclerView;
    private ArrayList<String> datas = new ArrayList<String>();
    private LinearLayoutManager mLlayoutmanager;
    private GridLayoutManager mGlayoutmanager;
    CharAdapter charad;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
        //切换屏幕时保存数据,如有数据,则不再进行数据的初始化
        if (savedInstanceState != null && savedInstanceState.getStringArrayList("data") != null) {  
            datas = savedInstanceState.getStringArrayList("data");
        }else {
            initData();
        }
        //竖屏线性展示
        mLlayoutmanager = new LinearLayoutManager(this);
        //横屏每行显示3个
        mGlayoutmanager = new GridLayoutManager(this,3);
        reviewonScreenChanged(getResources().getConfiguration());
        recyclerView.setAdapter(charad = new CharAdapter(this, datas));
        charad.setOnItemClickLitener(new OnItemClickLitener() {

            @Override
            public void onItemLongClick(View view, int position) {
            //这里要先使用这个数据再删除,因为一旦删除,就获取不到这个数据了,获取的就是下一个数据了
                Toast.makeText(OrientationChangeActivity.this, datas.get(position)+'\t'+"delete...", Toast.LENGTH_SHORT).show();
                charad.removeData(position);
            }

            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(OrientationChangeActivity.this, datas.get(position), Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void reviewonScreenChanged(Configuration newConfig) {
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            //横屏
            recyclerView.setLayoutManager(mGlayoutmanager);
        }else {
            //竖屏
            recyclerView.setLayoutManager(mLlayoutmanager);
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        reviewonScreenChanged(newConfig);
    }

    private void initData() {
        for (int i = 'A'; i <= 'z'; i++) {
            datas.add((char)i + "");
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putStringArrayList("data", datas);
    }
}


3.RecyclerView.Adapter

CharAdapter.java

/**
 * @author 尘笑ys
 *
 */
public class CharAdapter extends RecyclerView.Adapter<CharAdapter.MyViewHolder>{
//类型用自定义的ViewHolder

    private List<String> mDatas;
    private LayoutInflater mInflater;

    //RecyclerView目前需要自己来定义接口
    public interface OnItemClickLitener
    {
        //点击事件
        void onItemClick(View view, int position);
        //长按事件
        void onItemLongClick(View view , int position);
    }

    private OnItemClickLitener mOnItemClickLitener;

    //设置监听的方法,注意参数是CharAdapter.OnItemClickLitener而不是View.OnItemClickLitener
    public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
    {
        this.mOnItemClickLitener = mOnItemClickLitener;
    }

    //构造时传入数据,如果考虑数据解耦,可将数据赋值放到setData()中
    public CharAdapter(Context context, List<String> datas)
    {
        mInflater = LayoutInflater.from(context);
        mDatas = datas;
    }

    @Override
    //视图缓存创建
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        //视图缓存,在ViewHolder构造时获取视图控件
        MyViewHolder holder = new MyViewHolder(mInflater.inflate(
                R.layout.item_char, parent, false));
        return holder;
    }

    @Override
    //视图缓存的数据绑定
    public void onBindViewHolder(final MyViewHolder holder, final int position)
    {
        holder.tv.setText(mDatas.get(position));

        // 如果设置了回调,则设置点击事件
        if (mOnItemClickLitener != null)
        {
            holder.itemView.setOnClickListener(new OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    int pos = holder.getPosition();
                    //尽量在回调时处理逻辑,此处不进行处理,增加Adapter复用的可能
                    mOnItemClickLitener.onItemClick(holder.itemView, pos);
                }
            });

            holder.itemView.setOnLongClickListener(new OnLongClickListener()
            {
                @Override
                public boolean onLongClick(View v)
                {
                    int pos = holder.getPosition();
                    //尽量在回调时处理逻辑,此处不进行处理,增加Adapter复用的可能
                    mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
                    return false;
                }
            });
        }
    }

    @Override
    public int getItemCount()
    {
        return mDatas.size();
    }
    //需要自己定义,添加数据后需要调用notifyItemInserted(position),效果类似于ListView的notifyDataSetChanged()
    //但是这里会调用预设或者自定义的增加item动画
    public void addData(int position)
    {
        mDatas.add(position, "Insert One");
        notifyItemInserted(position);
    }

    //需要自己定义,添加数据后需要调用notifyItemRemoved(position),效果类似于ListView的notifyDataSetChanged()
    //但是这里会调用预设或者自定义的删除item动画
    public void removeData(int position)
    {
        mDatas.remove(position);
        notifyItemRemoved(position);
    }

    //视图缓存
    class MyViewHolder extends ViewHolder
    {

        TextView tv;

        //在构造方法中获取控件
        public MyViewHolder(View view)
        {
            super(view);
            tv = (TextView) view.findViewById(R.id.id_num);

        }
    }
}


4.布局

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

    <android.support.v7.widget.RecyclerView
        android:id="@+id/id_recyclerview"
        android:divider="#ffff0000"
        android:dividerHeight="10dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>


item_char.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/item_bg"
    android:layout_margin="2dp"
    android:gravity="center"
    >

    <TextView
        android:id="@+id/id_num"
        android:layout_width="100dp"
        android:layout_gravity="center"
        android:layout_height="100dp"
        android:gravity="center" />

</RelativeLayout>




5.瀑布流

在Adpater里面修改一下每个item的宽高,RecyclerView的LayoutManager再换成

mLlayoutmanager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
mGlayoutmanager = new StaggeredGridLayoutManager(5,StaggeredGridLayoutManager.HORIZONTAL);


就能看到瀑布流的效果啦。



6.总结与demo下载

这其实是一个十分简单的demo,你可以在此基础上去修改RecyclerView的分隔线以及载入删除动画。

RecyclerView的强大之处就是解耦,以往常常将所有的代码,分隔线、动画、逻辑处理、视图缓存等都放在Adapter中而导致Adapter根本无法复用。相信在大型项目中RecyclerView会有很好的表现以及编程体验。

demo下载

注意:本demo有一处疏漏,需要在Manifest.xml中对对应需要 横竖屏切换 的Activity添加一条属性:

android:configChanges="orientation"
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: