android实现六边形等不规则布局
在去年广告机项目中,UI设计出一个比较华丽的UI,但是对于我来说无从下手,我试过view的叠加并设置外边距实现,虽然勉强可以实现,但是获取单击焦点是有很多问题;
效果图如下:
最后只有另外想办法;我对viewgroup进行了自定义,并且自定义了每个按钮
源码:http://download.csdn.net/detail/hcb1230/6479979
以下是我的实现方式:
1.SpecailButton.java
public class SpecailButton extends TextView implements View.OnClickListener { private static final String TAG = "SpecailButton"; public static final int TEXT_ALIGN_LEFT = 0x00000001; public static final int TEXT_ALIGN_RIGHT = 0x00000010; public static final int TEXT_ALIGN_CENTER_VERTICAL = 0x00000100; public static final int TEXT_ALIGN_CENTER_HORIZONTAL = 0x00001000; public static final int TEXT_ALIGN_TOP = 0x00010000; public static final int TEXT_ALIGN_BOTTOM = 0x00100000; /** 控件画笔 */ private Paint paint; /** 文字的方位 */ private int textAlign; /** 文字的颜色 */ private int textColor; /** 控件的宽度 */ private int viewWidth; /** 控件的高度 */ private int viewHeight; /** 文本中轴线X坐标 */ private float textCenterX; /** 文本baseline线Y坐标 */ private float textBaselineY; private String text; private FontMetrics fm; private Context mContext; private boolean checked = false; public SpecailButton(Context context) { super(context); mContext = context; init(); } public SpecailButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mContext = context; init(); } public SpecailButton(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; init(); } /** * 变量初始化 */ private void init() { setOnClickListener(this); text = getText().toString(); setText(""); paint = new Paint(); paint.setTextSize(22); paint.setAntiAlias(true); paint.setTextAlign(Align.CENTER); //默认情况下文字居中显示 textAlign = TEXT_ALIGN_CENTER_HORIZONTAL | TEXT_ALIGN_CENTER_VERTICAL; //默认的文本颜色是黑色 textColor = Color.BLACK; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int wMode = MeasureSpec.getMode(widthMeasureSpec); int wSize = MeasureSpec.getSize(widthMeasureSpec); int hMode = MeasureSpec.getMode(heightMeasureSpec); int hSize = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(wSize, hSize); Log.i(TAG, "onMeasure()--wMode=" + wMode + ",wSize=" + wSize + ",hMode=" + hMode+ ",hSize=" + hSize); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { Log.i(TAG, "onLayout"); viewWidth = right - left; viewHeight = bottom - top; super.onLayout(changed, left, top, right, bottom); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //绘制控件内容 setTextLocation(text); canvas.drawText(text, textCenterX, textBaselineY, paint); } /** * 定位文本绘制的位置 */ private void setTextLocation(String text) { // paint.setTextSize(textSize); paint.setColor(textColor); fm = paint.getFontMetrics(); //文本的宽度 float textWidth = paint.measureText(text); float textCenterVerticalBaselineY = viewHeight / 2 - fm.descent + (fm.descent - fm.ascent) / 2; switch (textAlign) { case TEXT_ALIGN_CENTER_HORIZONTAL | TEXT_ALIGN_CENTER_VERTICAL: textCenterX = (float)viewWidth / 2; textBaselineY = textCenterVerticalBaselineY; break; case TEXT_ALIGN_LEFT | TEXT_ALIGN_CENTER_VERTICAL: textCenterX = textWidth / 2; textBaselineY = textCenterVerticalBaselineY; break; case TEXT_ALIGN_RIGHT | TEXT_ALIGN_CENTER_VERTICAL: textCenterX = viewWidth - textWidth / 2; textBaselineY = textCenterVerticalBaselineY; break; case TEXT_ALIGN_BOTTOM | TEXT_ALIGN_CENTER_HORIZONTAL: textCenterX = viewWidth / 2; textBaselineY = viewHeight - fm.bottom; break; case TEXT_ALIGN_TOP | TEXT_ALIGN_CENTER_HORIZONTAL: textCenterX = viewWidth / 2; textBaselineY = -fm.ascent; break; case TEXT_ALIGN_TOP | TEXT_ALIGN_LEFT: textCenterX = textWidth / 2; textBaselineY = -fm.ascent; break; case TEXT_ALIGN_BOTTOM | TEXT_ALIGN_LEFT: textCenterX = textWidth / 2; textBaselineY = viewHeight - fm.bottom; break; case TEXT_ALIGN_TOP | TEXT_ALIGN_RIGHT: textCenterX = viewWidth - textWidth / 2; textBaselineY = -fm.ascent; break; case TEXT_ALIGN_BOTTOM | TEXT_ALIGN_RIGHT: textCenterX = viewWidth - textWidth / 2; textBaselineY = viewHeight - fm.bottom; break; } } public interface OnClickListener { void onClick(View v, boolean checked); } private OnClickListener mListener; public void setOnClickListener(OnClickListener listener) { mListener = listener; } @Override public void onClick(View v) { checked = !checked; setBackgroundResource(checked ? 0 : R.drawable.logo); if (mListener != null) { mListener.onClick(v, checked); } } public String getTextString() { return text; } }
2.外面的父控件:
public class SpecailView extends ViewGroup { private static final String TAG = "SpecailView"; private static final int RADIU_COUNT = 8; private static final int PADDING = 10; private int childRadius; private int childWidth; private int childHeight; private int mChildCount; private int centerX ,centerY; public SpecailView(Context context) { super(context); Log.i(TAG, "SpecailView()"); } public SpecailView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); Log.i(TAG, "SpecailView( , , )"); } public SpecailView(Context context, AttributeSet attrs) { super(context, attrs); Log.i(TAG, "SpecailView( , )"); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int wMode = MeasureSpec.getMode(widthMeasureSpec); int wSize = MeasureSpec.getSize(widthMeasureSpec); int hMode = MeasureSpec.getMode(heightMeasureSpec); int hSize = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(wSize, hSize); centerX = wSize / 2; centerY = hSize / 2; childRadius = (wSize - PADDING * 2) / RADIU_COUNT; childWidth = childRadius * 2; childHeight = (int)(childRadius * Math.sqrt(3) / 2)*2; final int count = getChildCount(); for (int index = 0; index < count; index++) { View child = getChildAt(index); // measure child.measure(childWidth, childHeight); } if (mChildCount != count) { mChildCount = count; } // if (mChildCount > centers.size()) { computerPoint(centerX, centerY, childHeight); // } Log.i(TAG, "onMeasure()--childWidth="+childWidth+",childHeight="+childHeight); Log.i(TAG, "onMeasure()--wMode=" + wMode + ",wSize=" + wSize + ",hMode=" + hMode+ ",hSize=" + hSize); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { final int count = getChildCount(); int childLeft, childTop; for (int i = 0; i < count; i++) { View child = getChildAt(i); childLeft = (int)(centers.get(i).x-childRadius); childTop = (int)(centers.get(i).y-childHeight/2); child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); } Log.i(TAG, "onLayout()--changed=" + changed + ",left=" + left + ",top=" + top + ",right=" + right + ",bottom=" + bottom + ",count=" + count); } private int getCircleIndex(int i) { int index = 0; while (i > (3*index*index + 3*index)) { index ++; } return index; } /** * index start from 0 */ private int getCircleCount(int index) { if (index == 0) { return 1; } return index*6; } private void computerPoint(double a, double b, double h) { double sqrt3 = Math.sqrt(3); CircleCenteter c01 = new CircleCenteter(a, b); CircleCenteter c11 = new CircleCenteter(a, b-h); CircleCenteter c12 = new CircleCenteter(a + sqrt3*h/2, b - h/2); CircleCenteter c13 = new CircleCenteter(a + sqrt3*h/2, b + h/2); CircleCenteter c14 = new CircleCenteter(a, b + h); CircleCenteter c15 = new CircleCenteter(a - sqrt3*h/2, b + h/2); CircleCenteter c16 = new CircleCenteter(a - sqrt3*h/2, b - h/2); CircleCenteter c21 = new CircleCenteter(a, b-2*h); CircleCenteter c22 = new CircleCenteter(a + sqrt3*h/2, b-3*h/2); CircleCenteter c23 = new CircleCenteter(a + sqrt3*h, b - h); CircleCenteter c24 = new CircleCenteter(a + sqrt3*h, b); CircleCenteter c25 = new CircleCenteter(a + sqrt3*h, b + h); CircleCenteter c26 = new CircleCenteter(a + sqrt3*h/2, b + 3*h/2); CircleCenteter c27 = new CircleCenteter(a, b + 2*h); CircleCenteter c28 = new CircleCenteter(a - sqrt3*h/2, b + 3*h/2); CircleCenteter c29 = new CircleCenteter(a - sqrt3*h, b + h); CircleCenteter c210 = new CircleCenteter(a - sqrt3*h, b); CircleCenteter c211 = new CircleCenteter(a - sqrt3*h, b - h); CircleCenteter c212 = new CircleCenteter(a - sqrt3*h/2, b-3*h/2); centers.clear(); centers.add(c01); centers.add(c11); centers.add(c12); centers.add(c13); centers.add(c14); centers.add(c15); centers.add(c16); centers.add(c21); centers.add(c22); centers.add(c23); centers.add(c24); centers.add(c25); centers.add(c26); centers.add(c27); centers.add(c28); centers.add(c29); centers.add(c210); centers.add(c211); centers.add(c212); } public void setOnItemClick(SpecailButton.OnClickListener l) { int count = getChildCount(); for (int i = 0; i < count; i++) { ((SpecailButton)getChildAt(i)).setOnClickListener(l); } } private ArrayList<CircleCenteter> centers = new ArrayList<SpecailView.CircleCenteter>(7); class CircleCenteter { double x ,y; public CircleCenteter(double x, double y){ this.x = x; this.y = y; } } }
3.activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <com.qiang.testspecialview.SpecailView android:id="@+id/specail_view" android:layout_width="match_parent" android:layout_height="400dip" android:background="#78675645" > <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼0"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼1"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼2"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼3"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼4"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼5"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼6"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼7"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼8"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼9"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼10"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼11"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼12"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼13"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼14"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼15"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼16"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼17"/> <com.qiang.testspecialview.SpecailButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:gravity="center" android:text="婚礼18"/> </com.qiang.testspecialview.SpecailView> </RelativeLayout>
4.MainActivity.java
public class MainActivity extends Activity implements SpecailButton.OnClickListener { private SpecailView layout; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); layout = (SpecailView)findViewById(R.id.specail_view); layout.setOnItemClick(this); } @Override public void onClick(View v, boolean checked) { String text = ((SpecailButton)v).getTextString(); Toast.makeText(this, text + checked, Toast.LENGTH_SHORT).show(); } }
好了最后运行效果如下:
有需要工程的,源码:http://download.csdn.net/detail/hcb1230/6479979
转载自:http://www.sjsjw.com/kf_mobile/article/10_3422_10725.asp