由于涉及到工作内容保密的问题,所以无法提供源码,只能提供涉及该项功能的实现,本着开源和互相学习以及以后相同功能的重复利用的目的。
GridView虽然也支持横向滚动,但是并不支持代码控制,所以还是用到一个横向滚动来代替这个功能
<HorizontalScrollView android:id="@+id/hs_gridview" android:layout_width="610dp" android:layout_height="750dp" android:layout_weight="1" android:fillViewport="true" android:scrollbars="horizontal" > <LinearLayout android:layout_width="610dp" android:layout_height="490dp" > <cn.com.bcl.infoissuingsys.common.CommonGridView android:id="@+id/gridView" android:layout_width="1200dp" android:layout_height="490dp" android:layout_margin="0dp" android:horizontalSpacing="20dp" android:listSelector="@android:color/transparent" android:numColumns="20" android:scrollbarStyle="outsideInset" android:scrollbarThumbVertical="@drawable/scrollbar_vertical_thumb" android:scrollbarTrackVertical="@drawable/scrollbar_vertical_track" android:scrollbars="vertical" android:stretchMode="columnWidth" android:verticalSpacing="5dp" /> </LinearLayout> </HorizontalScrollView>
每个gridview的Item布局
<?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="match_parent" android:orientation="vertical" > <cn.com.bcl.infoissuingsys.common.CommonImageView android:id="@+id/zuoweiimage" android:layout_width="40dp" android:layout_height="35dp" android:scaleType="fitXY" android:src="@drawable/keyixuan"/> <cn.com.bcl.infoissuingsys.common.CommonTextView android:id="@+id/zuoweihao" android:layout_width="40dp" android:layout_height="35dp" android:textColor="#000000" android:textSize="15dp" android:text="01" android:gravity="center"/> </RelativeLayout>
绘制背景图片
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PorterDuff.Mode; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.LinearLayout.LayoutParams; public class RadarBgView extends SurfaceView implements SurfaceHolder.Callback { private String TAG = "RadarView"; private SurfaceHolder mHolder; private Context mCnxt; private int mSeatWidth = 410; private int mSeatHeight = 220; private int mStartSeatTop = 40; private int mLine = 0; private int mColumn=0; private int mLineNoWidth = 20; public RadarBgView(Context context) { super(context); } public RadarBgView(Context context,int line,int column) { super(context); this.mLine = line; this.mColumn = column; mCnxt = context; mHolder=this.getHolder(); mHolder.addCallback(this); setZOrderOnTop(true); mHolder.setFormat(PixelFormat.TRANSLUCENT); setFocusable(false); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { drawBg(mLine,mColumn); } @Override public void surfaceDestroyed(SurfaceHolder holder) { } /** change background */ public void notifyBgChange(){ } /**draw background by seat */ public void drawBg(int line,int column){ Paint paint=new Paint(); // paint.setColor(Color.BLACK); paint.setAntiAlias(true); paint.setFilterBitmap(true); paint.setDither(true); int divider = 1; /** onriginal 图片 */ Bitmap originalSeatBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.small); int originalWidth = originalSeatBitmap.getWidth(); int originalHeight = originalSeatBitmap.getHeight(); /** 新的高度和宽度 */ float newWidth = (mSeatWidth-mLineNoWidth-divider*(column-1))/column; float newHeight = (mSeatHeight-divider*(line-1))/line; /** 计算缩放比例 */ float scaleWidth = newWidth/originalWidth; float scaleHeight = newHeight/originalHeight; /**取得要缩放的参数 */ Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); /** 生成新图片 */ Bitmap newBm = Bitmap.createBitmap(originalSeatBitmap, 0, 0, originalWidth, originalHeight,matrix,true); originalSeatBitmap.recycle(); originalSeatBitmap = null; Paint testP=new Paint(); // paint.setColor(Color.BLACK); testP.setAntiAlias(true); testP.setTextSize(5); Canvas canvas = null; try { canvas = mHolder.lockCanvas(); synchronized (mHolder) { int offsetY = mStartSeatTop; for (int i = 0; i < line; i++) { canvas.drawText(String.valueOf(i+1), 6, offsetY+newBm.getHeight(), testP); int offsetX = mLineNoWidth; for (int j = 0; j < column; j++) { canvas.drawBitmap(newBm, offsetX, offsetY, paint); offsetX+=(newBm.getWidth()+divider); } offsetX=0; offsetY+=(newBm.getHeight()+divider); } } } catch (Exception e) { e.printStackTrace(); } finally { if (canvas != null) { mHolder.unlockCanvasAndPost(canvas); } } } }
绘制雷达区域的座位表和选择区域,实现点击事件,同步实际ScrollView和GridView的同步
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; public class RadarAreaView extends SurfaceView implements SurfaceHolder.Callback { private String TAG = "RadarAreaView"; private SurfaceHolder mHolder; private Handler mHandler; /** gridView 的 显示区域宽高 */ private int mDisplayWidth = 630; private int mDisplayHeight = 490; /** gridView real 高宽 */ private int mWholeWidth; private int mWholeHeight; /** 雷达座位区域长宽 */ private int mRadarSeatWidth = 410; private int mRadarSeatHeight = 260; /** 显示区域偏移量 */ private int mOffsetX = 0; private int mOffsetY = 40; /** 座位行列数 */ private int mLineNum = 0; private int mColumnNum = 0; /** radar和gridView的长高缩放比例 */ private float mScaleX; private float mScaleY; private int mLineNoWidth = 20; private int mStartSeatTop = 40; Bitmap mAreaBm = null; public RadarAreaView(Context context) { super(context); } public RadarAreaView(Context context, int line, int column,Handler handler) { super(context); mHolder = this.getHolder(); mHolder.addCallback(this); setZOrderOnTop(true); mHolder.setFormat(PixelFormat.TRANSLUCENT); this.mLineNum = line; this.mColumnNum = column; this.mHandler = handler; setFocusable(false); /** 初始化可视区域的图片大小 */ initAreaBm(); /** 雷达View与实际 View 的长宽比例 */ mScaleX = ((float)(mRadarSeatWidth-mLineNoWidth))/mWholeWidth; mScaleY = ((float)(mRadarSeatHeight-mStartSeatTop)/mWholeHeight); } /** * 根据实际比例初始化选择区域框的的图片大小 */ private void initAreaBm() { Bitmap originalBm = BitmapFactory.decodeResource(getResources(), R.drawable.area); int originalWidth = originalBm.getWidth(); int originalHeight = originalBm.getHeight(); int dividerX = 20; int dividerY = 5; /** original 图片 */ mWholeWidth = 40 * mColumnNum + dividerX * (mColumnNum - 1); mWholeHeight = 35 * mLineNum + dividerY * (mLineNum - 1); /** 计算缩放比例 */ float scaleWidth = ((float)mDisplayWidth) / mWholeWidth; float scaleHeight = ((float)mDisplayHeight) / mWholeHeight; /** 计算Area宽缩放后的长宽 */ float newAreaWidth = (mRadarSeatWidth-mLineNoWidth)*scaleWidth; float newAreaHeight = (mRadarSeatHeight-mStartSeatTop)*scaleHeight; /** 计算缩放比例 */ float newScaleWidth = newAreaWidth/originalWidth; float newScaleHeight = newAreaHeight/originalHeight; /**取得要缩放的参数 */ Matrix matrix = new Matrix(); matrix.postScale(newScaleWidth, newScaleHeight); /** 生成新图片 */ mAreaBm = Bitmap.createBitmap(originalBm, 0, 0, originalWidth, originalHeight, matrix, true); originalBm.recycle(); originalBm = null; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { drawArea(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { } /** clear && refresh Area by offsetX & offset Y */ public void drawArea() { Paint paint = new Paint(); paint.setAntiAlias(true); paint.setFilterBitmap(true); paint.setDither(true); Paint clearP = new Paint(); clearP.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); Canvas canvas = null; try { canvas = mHolder.lockCanvas(); synchronized (mHolder) { canvas.drawPaint(clearP); canvas.drawBitmap(mAreaBm, mOffsetX, mOffsetY, null); } } catch (Exception e) { e.printStackTrace(); } finally { if (canvas != null) { mHolder.unlockCanvasAndPost(canvas); } } } /** 点击雷达区域时,同步GridView显示的位置 */ @Override public boolean onTouchEvent(MotionEvent event) { final float x = event.getX(); final float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: /**caculate scroll */ /**雷达区域每个item的宽高 */ float xItemSize = (mRadarSeatWidth-mLineNoWidth)/mColumnNum; float yItemSize = (mRadarSeatHeight-mStartSeatTop)/mLineNum; int cornerX = 0; int cornerY = 0; /** 图像是左上角开始画的,所以为了让方框居于点击位置的中心,进行了偏移计算 */ cornerX=(int) (x-mAreaBm.getWidth()/2); cornerY=(int) (y-mAreaBm.getHeight()/2); int offsetX = 0; int offsetY = 0; /** 对于超出座位图的点击事件进行处理 */ if (cornerX<=mLineNoWidth) { offsetX = 0; } else if(cornerX>=(mRadarSeatWidth-mAreaBm.getWidth())){ offsetX = (int) ((mRadarSeatWidth-mLineNoWidth-mAreaBm.getWidth())); }else{ offsetX = (int) ((cornerX-mLineNoWidth)); } if (cornerY<=mStartSeatTop) { offsetY = 0; } else if(cornerY>=(mRadarSeatHeight-mAreaBm.getHeight())){ offsetY = (int) ((mRadarSeatHeight-mStartSeatTop-mAreaBm.getHeight())); }else{ offsetY = (int) ((cornerY-mStartSeatTop)); } int scrollX = (int) (offsetX/mScaleX); int position =(int) ((int)(offsetY/yItemSize)*mColumnNum+(int)(offsetX/xItemSize)); /** scroll seat gridView */ /** 从View发消息给Activity同步实际View的滚动 */ Message msg = new Message(); Bundle bundle = new Bundle(); bundle.putInt("scrollX", scrollX); bundle.putInt("position", position); bundle.putInt("linePosition", (int)(offsetY/yItemSize)); msg.setData(bundle); mHandler.sendMessage(msg); /**caculate and draw Area */ /** 根据点击位置和计算的左上角位置重绘选择区域 */ if (cornerX<=mLineNoWidth) { mOffsetX = mLineNoWidth; } else if(cornerX>=(mRadarSeatWidth-mAreaBm.getWidth())){ mOffsetX = (int) ((mRadarSeatWidth-mAreaBm.getWidth())); }else{ mOffsetX =(int) cornerX; } if (cornerY<=mStartSeatTop) { mOffsetY = mStartSeatTop; } else if(cornerY>=(mRadarSeatHeight-mAreaBm.getHeight())){ mOffsetY = (int) ((mRadarSeatHeight-mAreaBm.getHeight())); }else{ mOffsetY = (int) cornerY; } drawArea(); break; default: break; } return true; } /**GridView滚动时传入当前第一个可见的position 控制雷达的垂直方向的滚动同步 */ public void scrollVertical(int position){ float yItemSize = (mRadarSeatHeight-mStartSeatTop)/mLineNum; mOffsetY= (int) ((position/mColumnNum) * yItemSize)+mStartSeatTop; drawArea(); } /** 通过传入的HorizantalScrollView的move offset来控制雷达的水平方向的滚动同步 */ public void scrollHorizontal(int originalX){ mOffsetX =mLineNoWidth + (int)(originalX*mScaleX); drawArea(); } }
Fragment或者Activity中局部代码
/** * GridView */ private GridView mGridView; /** * HorizontalScrollView */ private HorizontalScrollView mHsGridView; private RelativeLayout mRelativeLayout_radar; private RadarAreaView mRav; private RadarBgView mRbv;
mRbv = new RadarBgView(mContext,mNumLine,mNumColumns); mRav = new RadarAreaView(mContext,mNumLine,mNumColumns,radarHandler); mRelativeLayout_radar.addView(mRbv); mRelativeLayout_radar.addView(mRav); /** 控制垂直滚动 */ mGridView.setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(final AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { View v = view.getChildAt(view.getFirstVisiblePosition()/mNumColumns); int[] location = new int[2]; if(null!=v){ v.getLocationOnScreen(location); if (mIsInitDefault) { mDefaultLocation = location[1]; mIsInitDefault = false; } mRav.scrollVertical(view.getFirstVisiblePosition()); } } }); /** HorizontalScrollView控制横向滚动同步 */ mHsGridView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: int offsetX = mHsGridView.getScrollX(); mRav.scrollHorizontal(offsetX); break; default: break; } return false; } });
从雷达区域来的消息处理,同步实际GridView的滚动
private Handler radarHandler = new Handler(){ public void handleMessage(Message msg) { Bundle bundle = msg.getData(); final int position = bundle.getInt("position"); final int linePosition = bundle.getInt("linePosition"); final int scrollX = bundle.getInt("scrollX"); mGridView.post(new Runnable() { @Override public void run() { mHsGridView.scrollTo(scrollX, (int) mGridView.getY()); mGridView.setSelection(position); } }); }; };
给自己mark一下
</div>