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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,057评论 25 707
  • 内容抽屉菜单ListViewWebViewSwitchButton按钮点赞按钮进度条TabLayout图标下拉刷新...
    皇小弟阅读 46,658评论 22 664
  • 百态人生景,风光永有别。 辛勤花朵艳,懒惰草无皆。 大海胸怀阔,温柔小溪携。 读书开眼界,雨露育诗杰。
    六月天气阅读 223评论 11 26
  • “爱”像风一样 “爱”像风一样, 留下空虚的情怀, 又一年绿绿的新麦。 曾几何时因为你它存在。 换了教师,换了窗外...
    甜蜜蜜_b52a阅读 420评论 0 0
  • 文/熠歆 家的味道,妈妈的味道! 这是正正板板的富源酸汤饭哟! 这碗汤饭里有酸菜、红豆、包谷饭,还有妈妈特意炒的下...
    熠歆阅读 558评论 5 2