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

时间: 2024-10-07 16:57:30

android实现六边形等不规则布局的相关文章

Android 第七课——UI布局

Android布局分为:线性布局.相对布局.表格布局.帧布局.网格布局五种 布局中的距离单位:dp.px.sp. 布局继承关系图: 1)熟悉几个常用属性 <Button android:id="@+id/loginName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/login&quo

【Android快速入门3】布局简介及例子

目前自学到布局部分,下面演示了不同布局的基本训练,涵盖的内容还是不错的,而且简单易懂,分享给大家. 1.LinearLayout流式布局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_pa

android菜鸟学习笔记6----android布局(一)

Android应用的UI组件都是继承自View类,View类表示的就是一个空白的矩形区域.常用的组件如TextView.Button.EditText等都直接或间接继承自View. 此外,View还有一个重要的子类ViewGroup,该类可以用来包含多个View组件,本身也可以当做一个View组件被其他的ViewGroup所包含,由此,可以构建出非常复杂的UI界面. 常用的布局管理器如FrameLayout.LinearLayout.RelativeLayout等都直接继承自ViewGroup.

(转)Android开发:5大布局方式详解

原文链接 http://liangruijun.blog.51cto.com/3061169/632532 Android中常用的5大布局方式有以下几种: 线性布局(LinearLayout):按照垂直或者水平方向布局的组件. 帧布局(FrameLayout):组件从屏幕左上方布局组件. 表格布局(TableLayout):按照行列方式布局组件. 相对布局(RelativeLayout):相对其它组件的布局方式. 绝对布局(AbsoluteLayout):按照绝对坐标来布局组件. 1. 线性布局

ANDROID自定义视图——仿瀑布布局(附源码)

简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量--onMeasure():决定View的大小 2.布局--onLayout():决定View在ViewGroup中的位置 3.绘制--onDraw():如何绘制这个View. 第3步的onDraw系统已经封装的很好了,基本不用我们来操心,只需要专注到1,2两个步骤就中好了. 第一步的测量,可以参考:(ANDROID自定义视图--onMeasure,MeasureSpec源码 流程 思路详解) 第二步的布局,可以参考:(AN

Android学习笔记-Activity的布局

线性布局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="fill_parent"     android:layout_height="fill_parent"

android ListView item有多重布局

android的listview的一个关键技术就是重绘利用. public View getView(int position, View convertView, ViewGroup parent) { return null; } 从Adatper的getview函数我们可以知道,函数提供了一个convertView的对象,这个对象是我们可以在一个列表中重复利用避免每次getview都进行重绘的关键.我们平常使用的都是大多是单个布局的item,所以我们可以通过建立一个holder就可以重复利

Android为各种组件或布局添加边框 以xml方式实现

1.在drawable文件夹下新建一个border.xml文件,然后将以下代码粘贴进去,可以根据自己的需要定义不同的颜色边框,或者是只有单边.两边或三边.四边的情况,非常好控制. 2.引用 在你需要使用的组件上或者是Layout布局上以background的方式去引用border.xml就可以了.项目中如果需要多种样式边框,当然你可以将border.xml命名成不同的文件名,然后分别加以引用即可(扯多了,大家都挺牛叉的)! <?xml version="1.0" encoding

Android侧滑菜单DrawerLayout(抽屉布局)实现

应用场景: 由于侧滑菜单有更好的用户体验效果,所以更多的App使用侧滑抽屉式菜单列表,如网易客户端.百度影音.爱奇艺等等.至此,侧滑菜单有了更多的使用需求. 知识点介绍: 实现侧滑菜单功能的方法有很多,如果开源的项目SlidingMenu,下载地址为https://github.com/jfeinstein10/SlidingMenu.该开源项目依赖于另一个开源项目ActionBarSherlock,下载地址为https://github.com/JakeWharton/ActionBarShe