玩了一段时间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;
}
});
}