Android自定义控件

里面包括了自定义图文框,自定义的仿ios菊花样式的ProgressBar,两种方法,一种是自己出来的,通过重写view,自己实现,其实这个重写就是自定义View的过程,另一种是网络上传的,直接通过定义动画转动实现,第一种方式拓展性比较好,做复杂点可以实现各种样式,当然仅仅是一个菊花的进度条,并不需要这么大费周章的写一个类。我练的是方法。



自定义控件,大体上的流程分为两种,一种是已有的控件,进行组合,一种是自己手动绘画出一个控件,当然,这里的绘画可以导入图片资源文件,通过转化为bitmap的对象再操作,如果是图片的适应操作,安卓官方文档有给出例子,我自己也认真看了下,感觉里面都是精华把。可以多看。我的笔记如下:

http://blog.csdn.net/u013755250/article/details/50224219


我看过箭头抽屉的开源项目,其实它也是写了这么一个Drawable的View,里面是通过画笔直接绘制图形,,再通过线性排插法进行变化,进行变化。


自定义控件,去google搜下,都有流程,大体是,measure,layout,draw。相对应的就是,测量,然后布局控件位置,再就是把控件的样子画出来。

我写组合控件的时候就深有体会。因为组合就不需要重写上述的三种方法,只要在构造方法中完成业务逻辑。这就有个问题了,构造方法是在new的时候就执行,它比View中的任何其他方法都要早执行。意味着,在构造方法中写控件,难免要用到控件的总的大小,可这时的所有getter方法获取的只都为0,因为根本就没测量过,就不会有数据。这时如何获取宽高呢?


我本来是想模仿自定属性时的方式,通过获取attrs.xml中属性定义的方式,来获取android:开头的属性,可是,肯能是思路有错,研究了好久,还是没找到正确的。后面想了个折中的方法,在dimens.xml中事先定义一个控件所要用的宽高,在UI的xml中设置时,就直接引用dimen的。这样就不存在重复定义的问题了,只要改一个地方的值,就可以整体适配,利于多次利用


个人觉得,写每个类的时候,都应该往多次利用的方向上靠。这样才复合继承的思想,可以多次利用,省去许多重复的业务。


效果图:






图文输入框:



package com.hs.cv;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.InputType;
import android.text.method.PasswordTransformationMethod;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.hs.customview.R;
import com.hs.cv.utils.BitmapUtil;

/**
 * 图文加载控件
 * 		使用方法,最好在dimen中第一控件的宽高,并且在xml中统一使用
 * 		一些属性设置,可以引用对象,重新设置
 *
 * @author Holy-Spirit
 *
 */
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public class CustomImageTxtView extends LinearLayout {

    /*
     * 控件内EditText对象
     */
    private EditText mText = null;
    /*
     * 控件内ImageView对象
     */
    private ImageView mImage = null;

    public CustomImageTxtView(Context context) {
        super(context);
    }

    public CustomImageTxtView(Context context, AttributeSet attrs) {
        super(context, attrs);

		/*
		 * 控件的宽
		 */
        final int vWidth = context.getResources().getDimensionPixelSize(
                R.dimen.defWidth);
		/*
		 * 控件的高
		 */
        final int vHeight = context.getResources().getDimensionPixelSize(
                R.dimen.defHeight);
		/*
		 * 控件内imag的高
		 */
        final int imgHeight = vHeight * 3 / 10;
		/*
		 * 控件内imag的宽
		 */
        final int imgWidth = imgHeight;
		/*
		 * 控件内imag的与其他控件的间隔
		 */
        final int imgMargin = vHeight / 5;

		/*
		 * 控件内容放置的重心
		 */
        final int contentGra = Gravity.CENTER_VERTICAL;

		/*
		 * 控件内txt文本的宽度
		 */
        final int txtWidth = vWidth - 2 * imgMargin - imgWidth;

		/*
		 * 控件内txt文本的高度
		 */
        final int txtHeight = vHeight;

		/*
		 * 属性的id
		 */
        int resId = -1;

		/*设置整个View的重心*/
        this.setGravity(contentGra);

		/*获取自定义的属性数组*/
        TypedArray mArray = context.obtainStyledAttributes(attrs,
                R.styleable.CustomImageTxtView);

		/*设置Image*/
        mImage = new ImageView(context);
        this.setImageLayoutParams(imgWidth, imgHeight, imgMargin);

		/*设置Edit*/
        mText = new EditText(context);
        this.setTextGravity(contentGra);
        this.setTextLayoutParams(txtWidth, txtHeight);
        this.hideBottomLine(context.getResources().getDrawable(
                R.drawable.round_background));
        this.setIsSingleLine(true);


		/*获取xml中设置的属性*/
        int length = mArray.getIndexCount();
        for (int i = 0; i < length; i++) {

            int attr = mArray.getIndex(i);
            switch (attr) {
                case R.styleable.CustomImageTxtView_Oriental:
				/*设置方向*/
                    resId = mArray.getInt(R.styleable.CustomImageTxtView_Oriental, 0);
                    this.setOrientation((resId == 1) ? LinearLayout.HORIZONTAL
                            : LinearLayout.VERTICAL);
                    break;

                case R.styleable.CustomImageTxtView_Text:
				/*设置文本内容*/
                    resId = mArray.getResourceId(R.styleable.CustomImageTxtView_Text, 0);
                    mText.setText(resId > 0 ? mArray.getResources().getText(resId)
                            : mArray.getString(R.styleable.CustomImageTxtView_Text));
                    break;

                case R.styleable.CustomImageTxtView_Src:
				/*设置图片资源*/
                    resId = mArray.getResourceId(R.styleable.CustomImageTxtView_Src, 0);

                    mImage.setImageBitmap(resId > 0 ? BitmapUtil
                            .decodeSampleBitmapFromResource(getResources(), resId,
                                    imgWidth, imgHeight) : BitmapUtil
                            .decodeSampleBitmapFromResource(getResources(),
                                    R.drawable.ic_launcher, imgWidth, imgHeight));
                    break;

                case R.styleable.CustomImageTxtView_Content:
				/*设置文本类型*/
                    resId = mArray.getInt(R.styleable.CustomImageTxtView_Content, 1);
                    if (resId == 1) {
                        this.setTextInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
                    } else if (resId == 2) {
                        this.setTextInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
                        this.setTextTransformationMethod();
                    } else {
                        this.setTextInputType(InputType.TYPE_CLASS_TEXT);
                    }
                    break;
                case R.styleable.CustomImageTxtView_TextColor:
				/*设置文字颜色*/
                    resId = mArray.getResourceId(
                            R.styleable.CustomImageTxtView_TextColor, 0);
                    if (resId > 0)
                        this.setTextColor(context.getResources().getColor(resId));
                    break;

                case R.styleable.CustomImageTxtView_TextSize:
				/*设置文字大小*/
                    resId = mArray.getResourceId(
                            R.styleable.CustomImageTxtView_TextSize, 0);
                    if (resId > 0)
                        this.setTextSize(context.getResources()
                                .getDimensionPixelSize(resId));
                    break;
                default:
                    break;
            }
        }

		/*添加控件到父控件*/
        addView(mImage);
        addView(mText);


		/*回收资源*/
        mArray.recycle();

    }


    /*
     * 设置密码输入
     */
    public void setTextTransformationMethod() {
        mText.setTransformationMethod(PasswordTransformationMethod
                .getInstance());

    }



    /*
     * 设置内容类型
     */
    public void setTextInputType(int type) {
        mText.setInputType(type);
    }



    /*
     * 设置内容字体大小
     */
    public void setTextSize(int size) {
        mText.setTextSize(size);

    }



    /*
     * 设置内容字体颜色
     */
    public void setTextColor(int color) {
        mText.setTextColor(color);
    }


    /*
     * 设置Imag布局
     */
    public void setImageLayoutParams(int reqWidth, int reqHeight, int margin) {
        LinearLayout.LayoutParams mParams = new LayoutParams(reqWidth,
                reqHeight);
        mParams.setMargins(margin, margin, margin, margin);
        mImage.setLayoutParams(mParams);
    }


    /*
     * 设置文本单行
     */
    public void setIsSingleLine(boolean isSingleLine) {
        mText.setSingleLine(isSingleLine);
    }


    /*
     * 隐藏原本EditText的下划线
     */
    public void hideBottomLine(Drawable bg) {
        mText.setBackground(bg);
    }


    /*
     * 设置文本内容重心
     */
    public void setTextGravity(int gravity) {
        mText.setGravity(gravity);
    }


    /*
     * 设置文本布局
     */
    public void setTextLayoutParams(int txtWidth, int txtHeight) {

        mText.setLayoutParams(new LayoutParams(txtWidth, txtHeight));

    }
}





自定义菊花样式ProgressBar:


基本的实现策略是在ondraw中画出菊花的图形,通过颜色轮转重画实现感觉图形一直在动的效果,你可以任意定义一组颜色,打到你想要的效果。可以在UI线程中定义一个handler,定时刷新

package com.hs.cv;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;

import com.hs.customview.R;

/**
 * 自定义菊花样式的Progress
 * UI线程定义handler定时刷新
 *
 * @author Holy-Spirit
 */

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@SuppressLint("DrawAllocation")
public class CustomProgressBar extends View
{

    /*
     * 画笔
     */
    private Paint mPaint = null;

    /*
     * 每个指针的颜色
     */
    private static final int[] colors = new int[]{R.color.color_top,
            R.color.color_right_top, R.color.color_right,
            R.color.color_right_bottom, R.color.color_bottom,
            R.color.color_left_bottom, R.color.color_left,
            R.color.color_left_top};

    /*
     * android res资源对象
     */
    private Resources res = null;

    /*
     * 颜色值轮转指针
     */
    private int i = 0;

    public CustomProgressBar(Context context)
    {
        super(context);

    }

    public CustomProgressBar(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        res = context.getResources();// 获取资源对象,用来获取color值
    }

    public void refreshView()
    {
        invalidate();// 触发onDraw()方法,重绘Progress
    }

    /*
     * color循环变化
     */
    private int calculateIndex(int in)
    {
        return in % (colors.length - 1);
    }

    /*
     * 设置指针颜色
     */
    public void setLineColor(int index)
    {
        mPaint.setColor(res.getColor(colors[calculateIndex(index)]));
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);

        final float roundWidth;
        final int width = canvas.getWidth();
        final int height = canvas.getHeight();
        roundWidth = width > height ? height : width;
        final float halfRoundWidth = roundWidth / 2;// 获取画布的半长
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(roundWidth / 15);// 设置为画布的十五分之一
        float f1 = halfRoundWidth / 5;
        float f2 = (float) Math.sqrt(f1 * f1 / 2);// 中心点到指针的长度在x,y轴上的投影
        float f3 = (float) Math.sqrt(f1 * f1 * 9) / 2;//指针长在x,y轴上的投影
        float f5 = halfRoundWidth - f3 - f1;//画布四哥点到指针的长度在x,y轴上的投影

        // top
        this.setLineColor(0 + i);
        canvas.drawLine(halfRoundWidth, halfRoundWidth / 5, halfRoundWidth,
                halfRoundWidth / 5 * 4, mPaint);

        // right top
        this.setLineColor(1 + i);
        canvas.drawLine(roundWidth - f5, f5, halfRoundWidth + f2,
                halfRoundWidth - f2, mPaint);

        // right
        this.setLineColor(2 + i);
        canvas.drawLine(halfRoundWidth / 5 * 9, halfRoundWidth,
                halfRoundWidth / 5 * 6, halfRoundWidth, mPaint);

        // right bottom
        this.setLineColor(3 + i);
        canvas.drawLine(roundWidth - f5, roundWidth - f5, halfRoundWidth + f2,
                halfRoundWidth + f2, mPaint);

        // bottom
        this.setLineColor(4 + i);
        canvas.drawLine(halfRoundWidth, halfRoundWidth / 5 * 9, halfRoundWidth,
                halfRoundWidth / 5 * 6, mPaint);

        // left bottom
        this.setLineColor(5 + i);
        canvas.drawLine(f5, roundWidth - f5, halfRoundWidth - f2,
                halfRoundWidth + f2, mPaint);

        // left
        this.setLineColor(6 + i);
        canvas.drawLine(halfRoundWidth / 5, halfRoundWidth,
                halfRoundWidth / 5 * 4, halfRoundWidth, mPaint);
        // // left top
        this.setLineColor(7 + i);
        canvas.drawLine(f5, f5, halfRoundWidth - f2, halfRoundWidth - f2,
                mPaint);

        i++;
    }

}



通过定义的动画的方式实现菊花样式的Progressbar:



第一步:



<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/pic_rotate"
    android:pivotX="50%"
    android:pivotY="50%" />


引用的图片就是你要让它动的图片





第二部在UI的xml中引用




   <ProgressBar
        android:id="@+id/logining"
        android:layout_width="15dp"
        android:layout_height="15dp"
        android:indeterminateDrawable="@drawable/circle_loading"
        android:layout_alignTop="@+id/cancel"
        android:layout_alignRight="@+id/count"
        android:layout_alignEnd="@+id/count"/>


demo下载:


http://download.csdn.net/detail/u013755250/9341283


基于SSM框架的智能家政保洁预约系统,是一个旨在提高家政保洁服务预约效率和管理水平的平台。该系统通过集成现代信息技术,为家政公司、家政服务人员和消费者提供了一个便捷的在线预约和管理系统。 系统的主要功能包括: 1. **用户管理**:允许消费者注册、登录,并管理他们的个人资料和预约历史。 2. **家政人员管理**:家政服务人员可以注册并更新自己的个人信息、服务类别和服务时间。 3. **服务预约**:消费者可以浏览不同的家政服务选项,选择合适的服务人员,并在线预约服务。 4. **订单管理**:系统支持订单的创建、跟踪和管理,包括订单的确认、完成和评价。 5. **评价系统**:消费者可以在家政服务完成后对服务进行评价,帮助提高服务质量和透明度。 6. **后台管理**:管理员可以管理用户、家政人员信息、服务类别、预约订单以及处理用户反馈。 系统采用Java语言开发,使用MySQL数据库进行数据存储,通过B/S架构实现用户与服务的在线交互。系统设计考虑了不同用户角色的需求,包括管理员、家政服务人员和普通用户,每个角色都有相应的权限和功能。此外,系统还采用了软件组件化、精化体系结构、分离逻辑和数据等方法,以便于未来的系统升级和维护。 智能家政保洁预约系统通过提供一个集中的平台,不仅方便了消费者的预约和管理,也为家政服务人员提供了一个展示和推广自己服务的机会。同时,系统的后台管理功能为家政公司提供了强大的数据支持和决策辅助,有助于提高服务质量和管理效率。该系统的设计与实现,标志着家政保洁服务向现代化和网络化的转型,为管理决策和控制提供保障,是行业发展中的重要里程碑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值