Android将ListView逆时针旋转90°实现横向滑动

screen4.gif
玩了一段时间Android,最近在实现一些常用的控件封装:项目GitHub地址https://github.com/tikeyc/TikeycAndroid 。这几天想封装一个横向滑动的listView,但发现Android没有像iOS那样的UICollectionView控件,似乎只有一个HorizontalScrollView,后来发现Android有个RecyclerView设置setLayoutManager的setOrientation为HORIZONTAL即可简单实现,不过还是回到最初我的想法去尝试一下。

当然最后肯定是用RecyclerView控件实现(刚学自学Android开发的时候居然没发现RecyclerView,惭愧的很,不过这个控件也是2014年support.v7包出现才有的)。

前期实现思路有:

1.使用GridView添加到HorizontalScrollView上,设置column为item数量count,width为count*itemWidth,这样没有复用性了性能低;
2.根据listView的复用原理,结合HorizontalScrollView自定义一个横向滑动的控件,需要敲一些代码;

中期实现思路:

记得很久以前刚学iOS的时候第一次看到横向滑动的UITableView,想实现它,当时的思路就是将UITableView逆时针旋转90°,然后将UITableViewCell顺时针旋转90°(当然现在肯定是用UICollectionView)。这里我把这个思路用到Android的实现上,将ListView逆时针旋转90°,然后将item顺时针旋转90°,果不其然,成功了!小爽一把。源码地址:https://github.com/tikeyc/TikeycAndroid 封装详情代码见THorizontalListView类
目前还存在一个小问题:就是如果item不是正方形,因为默认旋转是以item中心点旋转,item会出现偏移的问题,需要根据你具体的item的尺寸修改旋转中心点,具体见下面需要了解的技术点.

这里也提一个问题,这个旋转不像iOS那样,iOS先旋转后重新设置想要的frame不会有问题,因初入Android开发,先setRotation,然后旋转后使用setLayoutParams设置想要的frame不成功,旋转中心位置就跟着变了。来个吊大的提供一个方法能像iOS那样。

后期实现思路:

RecyclerView是support.v7包中的控件,可以说是ListView和GridView的增强升级版。RecyclerView设置setLayoutManager的setOrientation为HORIZONTAL即可简单实现

需要了解的技术点:
/**逆时针旋转90°
     *setRotation(-90); 默认是已view的中心点旋转,所以先根据最终旋转后显示的位置,先更改view的位置到初始旋转的合适位置,然后再旋转90°就会显示在你所希望的位置
     * 如下图:由默认的竖向已中心点旋转为横向
             * * * * *
             *       *
             *       *
       * * * * * * * * * * *
       *     *       *     *
       *     *       *     *
       * * * * * * * * * * *
             *       *
             *       *
             * * * * *
     */
//此方法用于获取View在Z轴上的旋转角度  
public float android.view.View.getRotation()  
  
//此方法用于获取View在X轴上的旋转角度  
public float android.view.View.getRotationX()  
  
//此方法用于获取View在Y轴上的旋转角度  
public float android.view.View.getRotationY()  
  
//设置View在Z轴上的旋转角度  
public void android.view.View.setRotation(float rotation)  
  
//设置View在X轴上的旋转角度  
public void android.view.View.setRotationX(float rotationX)  
  
//设置View在Y轴上的旋转角度  
public void android.view.View.setRotationY(float rotationY)  
  
//设置View旋转中心点的X坐标。  
public void android.view.View.setPivotX(float pivotX)  
  
//设置View旋转中心点的Y坐标。  
public void android.view.View.setPivotX(float pivotX)  
 
//设置摄像机的与旋转目标在Z轴上距离  
void android.view.View.setCameraDistance(float distance)
具体实现:

package com.tikeyc.tikeycandroid.custom.ScrollView;
import android.content.Context;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;

/**
 * Created by public1 on 2017/6/2.
 */

public class THorizontalListView extends ListView {

    private int listView_width;
    private int listView_height;
    private THorizontalListAdapter horizontalListAdapter;

    public THorizontalListView(Context context) {
        this(context,null);
    }

    public THorizontalListView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public THorizontalListView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        init();
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
    }

    private void init() {

        rotationListView();

        horizontalListAdapter = new THorizontalListAdapter();
        setAdapter(horizontalListAdapter);
    }

    /**逆时针旋转90°
     *setRotation(-90); 默认是已view的中心点旋转,所以先根据最终旋转后显示的位置,先更改view的位置到初始旋转的合适位置,然后再旋转90°就会显示在你所希望的位置
     * 如下图:由默认的竖向已中心点旋转为横向
             * * * * *
             *       *
             *       *
       * * * * * * * * * * *
       *     *       *     *
       *     *       *     *
       * * * * * * * * * * *
             *       *
             *       *
             * * * * *
     */
    private void rotationListView() {

        ViewTreeObserver viewTreeObserver = getViewTreeObserver();
        viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                getViewTreeObserver().removeOnPreDrawListener(this);
                int left = getLeft();
                int top = getTop();
                int right = getRight();
                int bottom = getBottom();
                int width = right - left;
                int height = bottom - top;
                Log.e("TAG","getWidth():" + getWidth() + "--" + "getHeight():" + getHeight());
                Log.e("TAG","left:" + left + "--" + "top:" + top + "--" + "width:" + width + "--" + "height:" + height);

                LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
                layoutParams.leftMargin = layoutParams.leftMargin + (width - height)/2;//将view已到默认的旋转中心点
                layoutParams.topMargin = layoutParams.topMargin + (height - width)/2;//将view已到默认的旋转中心点
                listView_width = width;
                listView_height = height;
                layoutParams.width = height;//旋转后的宽是旋转前的高
                layoutParams.height = width;//旋转后的高是旋转前的宽
                setLayoutParams(layoutParams);
                Log.e("TAG","left:" + left + "--" + "top:" + top + "--" + "width:" + width + "--" + "height:" + height);
                setRotation(-90);
                Log.e("TAG","left2:" + getLeft() + "--" + "top2:" + getTop() + "--" + "width:" + width + "--" + "height:" + height);
                return true;
            }
        });
    }


    public class THorizontalListAdapter extends BaseAdapter {

        @Override
        public int getCount() {
            if (dataSource != null) return dataSource.getCount();
            return 0;
        }

        @Override
        public Object getItem(int i) {
            if (dataSource != null) return dataSource.getItem(i);
            return null;
        }

        @Override
        public long getItemId(int i) {
            if (dataSource != null) return dataSource.getItemId(i);
            return 0;
        }

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {

            if (dataSource != null) {
                view = dataSource.getView(i,view,viewGroup);
                //再将item顺时针旋转90° 宽是旋转后的高(item的宽度),高是旋转后的宽(item的高度)
                ViewTreeObserver treeObserver = view.getViewTreeObserver();
                final View finalView = view;
                treeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                    @Override
                    public boolean onPreDraw() {
//                        int width = finalView.getWidth();
//                        int height = finalView.getHeight();
//                        finalView.setPivotX(width/2);
//                        finalView.setPivotY(listView_height/2);
                        AbsListView.LayoutParams layoutParams = new AbsListView.LayoutParams(listView_height,listView_height);
                        finalView.setLayoutParams(layoutParams);
                        finalView.setRotation(90);

                        return true;
                    }
                });

                return view;
            }

            return view;
        }
    }


    private THorizontalListAdapterDatasource dataSource;

    public void setDataSource(THorizontalListAdapterDatasource dataSource) {
        this.dataSource = dataSource;
        horizontalListAdapter.notifyDataSetChanged();

    }

    public THorizontalListAdapterDatasource getDataSource() {
        return dataSource;
    }

    public interface THorizontalListAdapterDatasource {
        int getCount();
        Object getItem(int i);
        long getItemId(int i);
        View getView(int i, View view, ViewGroup viewGroup);
    }

}
如何使用:
见类TReleaseFragment或者THomeUserAdapter
使用的主要关键代码:
THorizontalListView horizontalListView = (THorizontalListView) mView.findViewById(R.id.tHorizontalListView);
        horizontalListView.setBackgroundColor(Color.BLUE);
        horizontalListView.setDataSource(new THorizontalListView.THorizontalListAdapterDatasource() {

            class ViewHolder {

            }

            @Override
            public int getCount() {
                return 20;
            }

            @Override
            public Object getItem(int i) {
                return null;
            }

            @Override
            public long getItemId(int i) {
                return 0;
            }

            @Override
            public View getView(int i, View view, ViewGroup viewGroup) {
                ViewHolder viewHolder;
                if (view == null) {
                    viewHolder = new ViewHolder();
                    view = View.inflate(getContext(),R.layout.release_home_image_list_item,null);
                    //宽是高,高是宽
                    view.setTag(viewHolder);

                } else {
                    viewHolder = (ViewHolder) view.getTag();
                }
                return view;
            }
        });
    }

你可能感兴趣的:(Android将ListView逆时针旋转90°实现横向滑动)