Android自定義控件
1.組合控件。
幾個現有控件,組合起來,達到使用的目的。初始化時,新佈局填充到控件上。
組合控件定義一個密碼輸入框,右側可以點擊圖標,來切換密碼是顯示或隱藏。
佈局文件:由editText和img組成。
<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="60dp"
tools:context="com.example.yijian.testanination.MainActivity">
<EditText
android:id="@+id/et_password"
android:hint="請輸入密碼"
android:singleLine="true"
android:maxLength="50"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@null"/>
<RelativeLayout
android:id="@+id/gy_rl_edittext_right"
android:layout_width="48dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:gravity="center"
>
<ImageView
android:id="@+id/gy_img_edittext_right"
android:background="@drawable/gy_password_eye_off"
android:clickable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>
</RelativeLayout>
定義控件類繼承RelativeLayout
public class MyTextView extends RelativeLayout { private RelativeLayout layout = null; private EditText mEtPassword; private RelativeLayout mLlRightPic; public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public MyTextView(Context context) { super(context); init(context); } /** * 初始化 * @param context */ private void init(Context context) { if (layout == null) layout = (RelativeLayout) ((LayoutInflater) (context.getSystemService(Context.LAYOUT_INFLATER_SERVICE))). inflate(R.layout.my_textview,this); mEtPassword = (EditText) layout.findViewById(R.id.et_password); mLlRightPic = (RelativeLayout) layout.findViewById(R.id.gy_rl_edittext_right); mLlRightPic.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //右側圖標點擊時,切換 顯示密碼和隱藏密碼的設置 } }); } public String getText(){ //返回用戶輸入的密碼 return mEtPassword.getEditableText().toString(); } }
代碼中使用:當做正常控件來使用。
<com.example.yijian.testanination.MyTextView android:layout_width="match_parent" android:layout_height="60dp"> </com.example.yijian.testanination.MyTextView>
2.繼承現有控件,實現所需功能。
有些情況下直接繼承現有控件,也十分方便。
這種情況要求,對要繼承的類較爲熟悉。
比如防止Button控件連續點擊,可以重寫button
/** * Created by gj on 2016/5/11. * 統一按鈕 */ public class GyButton extends Button { public GyButton(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public GyButton(Context context) { super(context); init(context); } //button_selecter private void init(Context context) { setBackgroundDrawable(getResources().getDrawable(R.drawable.button)); setTextSize(16); setTextColor(context.getResources().getColor(R.color.textcolor_on_up_widget)); } @Override public boolean performClick() { if(DataTimeUtil.buttonIsDoubleClick()){ return false; }else{ return super.performClick(); } } }
ViewPager添加小圓點指示器
onDraw中去繪製圓點。getAdapter能拿到適配器。getCount可以拿到元素的數量。getCurrentItem當前索引。
這樣就可以自動的設置指示器。
/** * Created by gj on 2017/2/8. */ public class IndicatorViewPager extends ViewPager{ Context context; Paint paint; List<Map<String, String>> urls; public IndicatorViewPager(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; paint = new Paint(); } public void setData(List<Map<String, String>> data) { urls.clear(); for (int i = 0; i < data.size(); i++) { urls.add(data.get(i)); } if(urls.size()>0){ this.setVisibility(View.VISIBLE); }else{ this.setVisibility(View.GONE); } } @Override public void draw(Canvas canvas) { super.draw(canvas); drawCycle(canvas); } private void drawCycle(Canvas canvas) { canvas.save(); canvas.translate(getScrollX(), getScrollY()); int count = 0; if (this.getAdapter() != null) { count = this.getAdapter().getCount(); } int select = getCurrentItem(); float density = getContext().getResources().getDisplayMetrics().density; int itemWidth = (int) (11 * density); int itemHeight = itemWidth / 2; int x = (getWidth() - count * itemWidth)/2; int y = getHeight() - itemWidth; int minItemHeight = (int) ((float) itemHeight * 0.8F); paint.setAntiAlias(true); paint.setStyle(Paint.Style.FILL); for (int i = 0; i < count; i++) { if (select == i) { paint.setColor(0xFF666666); canvas.drawCircle((x + itemWidth * i + itemWidth / 2)+350, y, minItemHeight, paint); } else { paint.setColor(0xFFe6e6e6); canvas.drawCircle((x + itemWidth * i + itemWidth / 2)+350, y, minItemHeight, paint); } } canvas.restore(); } }
實現文字的垂直滾動效果。
繼承TextSwitcher(文字轉換器)。即可正常設置文字。
/** * 自動垂直滾動的TextView */ public class VerticalScrollTextView extends TextSwitcher implements ViewSwitcher.ViewFactory { private Context mContext; //mInUp,mOutUp分別構成向下翻頁的進出動畫 private Animation mInAnimation; private Animation mOutAnimation; public VerticalScrollTextView(Context context) { this(context, null); } public VerticalScrollTextView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; init(); } private void init() { //設置TextView的產生,會調用ViewFactory.makeView() setFactory(this); //設置出入動畫 mInAnimation = AnimationUtils.loadAnimation(mContext, R.anim.vertical_in); mOutAnimation = AnimationUtils.loadAnimation(mContext, R.anim.vertical_out); setInAnimation(mInAnimation); setOutAnimation(mOutAnimation); } //這裏返回的TextView,就是我們看到的View,可以設置自己想要的效果 @Override public View makeView() { TextView textView = new TextView(mContext); textView.setTextSize(36); // textView.setSingleLine(true); // textView.setGravity(Gravity.CENTER_VERTICAL); return textView; } }
動畫vertical_in
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="1000" android:fromYDelta="100%p" android:toYDelta="0%p" /> </set>
verrical_out
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="1000" android:fromYDelta="0%p" android:toYDelta="-100%p" /> </set>
3.繼承View或者ViewGroup
3.1繼承View
Values/attrs.xml
<?xml version="1.0"
encoding="utf-8"?>
<resources>
<attr name="text"format="string"
/>
<attr name="textSize"format="dimension"
/>
<declare-styleable name="CustomTxtView">
<attr name="text"/>
<attr name="textSize"/>
</declare-styleable>
</resources>
CustomerView繼承成View類
構造方法走三個參數的。
public CustomerView(Context context) { this(context,null); } public CustomerView(Context context, AttributeSet attrs) { this(context, attrs,0); }
public CustomerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); /** * 獲得我們所定義的自定義樣式屬性 */ TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTxtView, defStyleAttr, 0); int n = a.getIndexCount(); for (int i = 0; i < n; i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.CustomTxtView_text: this.text = a.getString(attr); break; case R.styleable.CustomTxtView_textSize: // 默認設置爲16sp,TypeValue也可以把sp轉化爲px mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); break; } } mPaint = new Paint(); mPaint.setTextSize(mTitleTextSize); mBound = new Rect(); mPaint.getTextBounds(text, 0, text.length(), mBound); }
實現onDraw、onMeasure
@Override protected void onDraw(Canvas canvas) { mPaint.setColor(Color.YELLOW); canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint); mPaint.setColor(Color.BLACK); canvas.drawText(text, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint); } // 先了解MeasureSpec的specMode,一共三種類型: // EXACTLY:一般是設置了明確的值或者是MATCH_PARENT // AT_MOST:表示子佈局限制在一個最大值內,一般爲WARP_CONTENT // UNSPECIFIED:表示子佈局想要多大就多大,很少使用 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width; int height ; if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { mPaint.setTextSize(mTitleTextSize); mPaint.getTextBounds(text, 0, text.length(), mBound); float textWidth = mBound.width(); int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight()); width = desired; } if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { mPaint.setTextSize(mTitleTextSize); mPaint.getTextBounds(text, 0, text.length(), mBound); float textHeight = mBound.height(); int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom()); height = desired; } setMeasuredDimension(width, height); }
在佈局中使用(需要添加約束)
xmlns:customtext="http://schemas.android.com/apk/res-auto"
<com.example.yijian.testanination.widget.CustomerView android:layout_width="wrap_content" android:layout_height="wrap_content" customtext:text="12378" customtext:textSize="16sp" />