Android将ListView逆时针旋转90°实现横向滑动
16lz
2021-01-23
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】如何让跑马灯跑起来-控件请求焦点
- Android控件GridView的使用
- android获取GPS位置信息
- android 相对布局中的 控件布局
- Android中自定义switch控件样式
- android中listview控件覆盖了其它控件使下面的其它控件不显示
- 自定义控件 - 圆形缓冲进度条
- Android GPS获取当前位置信息
- Android支持展开/收缩功能的列表控件