Android自定义控件

第一步:定义一个有图片和文本的布局:

  • <?xmlversion="1.0"encoding="utf-8"?> 
  • <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"  
  •     android:orientation="horizontal"  
  •     android:layout_width="wrap_content"  
  •     android:layout_height="wrap_content"  
  •     >  
  • <ImageView  
  •     android:id="@+id/widget_image_text_btn_Img"  
  •     android:layout_width="wrap_content"  
  •     android:layout_height="wrap_content"  
  •     />  
  • <TextView  
  •     android:id="@+id/widget_image_text_btn_TV"  
  •     android:layout_width="wrap_content"  
  •     android:layout_height="wrap_content"  
  •     android:textColor="#000000"  
  •     android:layout_marginLeft="8dip"  
  •     android:layout_gravity="center_vertical"  
  •     />  
  • </LinearLayout>  

第二步:定义一个与这个布局对应的类:

  • publicclass ImgTextBtnH extends LinearLayout { 
  •  
  •     privatestaticfinal String TAG = ImgTextBtnH.class.getSimpleName(); 
  •      
  •     private ImageView mImg;  
  •     private TextView  mTV;  
  •     private Button mBtn; 
  •     private Context mContext = null
  •   
  •     public ImgTextBtnH(Context context) {  
  •         this(context, null);  
  •         mContext = context; 
  •     }  
  •   
  •     protectedvoid inflaterLayout(Context context) { 
  •         // 导入布局  
  •         LayoutInflater.from(context).inflate(R.layout.widget_image_text_btn_horizontal_layout, this, true);  
  •     } 
  •      
  •      
  •     @SuppressLint("NewApi"
  •     public ImgTextBtnH(Context context, AttributeSet attrs) {  
  •         super(context, attrs);  
  •         mContext = context; 
  •          
  •         Resources.Theme theme = context.getTheme(); 
  •          
  •         inflaterLayout(context); 
  •         // 导入布局  
  • //        LayoutInflater.from(context).inflate(R.layout.widget_image_text_btn_layout, this, true);  
  •         mImg = (ImageView) findViewById(R.id.widget_image_text_btn_Img);  
  •         mTV = (TextView) findViewById(R.id.widget_image_text_btn_TV);  
  •         mBtn = (Button) findViewById(R.id.widget_image_text_btn_Btn); 
  •          
  •         //不能够使用ImageView的click方法, 在android里点击事件消息是从内向外传递的,设置了false之后才能传递出来给LinearLayout 
  •         mImg.setClickable(false); //谢谢 Brightshadow11111 朋友的提醒 
  •          
  •         TypedArray typeArray = context.obtainStyledAttributes(attrs, 
  •                 R.styleable.ImgTextBtn); 
  •         if (typeArray == null) { 
  •             return
  •         } 
  •          
  •         int count = typeArray.getIndexCount(); 
  •         int resId = 0
  •         for (int i = 0; i < count; i++) { 
  •             int attr = typeArray.getIndex(i); 
  •             switch(attr) { 
  •             case R.styleable.ImgTextBtn_ImgDraw: 
  •                 Drawable background = typeArray.getDrawable(attr); 
  •                 int sdk = android.os.Build.VERSION.SDK_INT; 
  •                 if(sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) { 
  •                     mImg.setBackgroundDrawable(background); 
  •                 } else
  •                     mImg.setBackground(background); 
  •                 } 
  •                 break
  •             case R.styleable.ImgTextBtn_ImgDrawWidth: 
  •                 int imageWidth = typeArray.getDimensionPixelSize(attr, -1); 
  •                 mImg.setMaxWidth(imageWidth); 
  •                 mImg.setMinimumWidth(imageWidth); 
  •                 break
  •             case R.styleable.ImgTextBtn_ImgDrawHeight: 
  •                 int imageHeight = typeArray.getDimensionPixelSize(attr, -1); 
  •                 mImg.setMaxHeight(imageHeight); 
  •                 mImg.setMinimumHeight(imageHeight); 
  •                 break
  •             case R.styleable.ImgTextBtn_ImgDrawMinWidth: 
  •                 int imageMinWidth = typeArray.getDimensionPixelSize(attr, -1); 
  •                 mImg.setMinimumHeight(imageMinWidth); 
  •                 break
  •             case R.styleable.ImgTextBtn_ImgDrawMinHeight: 
  •                 int imageMinHeight = typeArray.getDimensionPixelSize(attr, -1); 
  •                 mImg.setMinimumHeight(imageMinHeight); 
  •                 break
  •             case R.styleable.ImgTextBtn_ImgDrawMaxHeight: 
  •                 int imageMaxHeight = typeArray.getDimensionPixelSize(attr, -1); 
  •                 mImg.setMaxHeight(imageMaxHeight); 
  •                 break
  •             case R.styleable.ImgTextBtn_ImgDrawMaxWidth: 
  •                 int imageMaxWidth = typeArray.getDimensionPixelSize(attr, -1); 
  •                 mImg.setMaxWidth(imageMaxWidth); 
  •                 break
  •             case R.styleable.ImgTextBtn_TVText: 
  •                 mTV.setText(typeArray.getText(attr)); 
  •                 break
  •             case R.styleable.ImgTextBtn_TVTextSize: 
  •                 mTV.setTextSize(typeArray.getDimensionPixelSize(attr, 15)); 
  •                 break
  •             } 
  •         } 
  •         typeArray.recycle(); 
  •     }  
  •      
  • <span style="color: rgb(255, 0, 0);">    @Override 
  •     publicvoid refreshDrawableState() { 
  •         // TODO Auto-generated method stub 
  •         super.refreshDrawableState(); 
  •         //------------接下来处理联动效果,关键代码,请认真看------------------- 
  •         //------------ ImageView控件的联动刷新 ------------------- 
  •         Drawable imgDrawable = mImg.getBackground(); //获取drawable资源 
  •         Log.d(TAG, "drawable = " + imgDrawable); 
  •         if (imgDrawable != null && imgDrawable.isStateful()) { 
  •             //关键中的关键,根据当前状态设置drawable的状态,本来应该是LinearLayout的getDrawableState()状态, 
  •             //但是现在是实现联动效果,而且获取的ImageView的getDrawState()结果不对。 
  •             imgDrawable.setState(this.getDrawableState());  
  •         } 
  •          
  •         //------------- TextView的联动刷新, 抱歉, 无法刷新 ------------------ 
  •         //这块代码很快写出来了,但是写出来后发现,颜色总是停留在最后一次的颜色上,后面再点击都无法改变颜色了, 
  •         //才恍然大悟,mTV.setTextColor()是设置TextView内部的ColorStateList对象的,这样会清掉原先的 
  •         //res/color/colorSelector.xml里的设置,导致只有一种颜色值。应该赋值给TextView内部的private int mCurTextColor; 
  •         //可惜没有并设置mCurTextColor值的接口,不知到使用反射能否做到,有兴趣朋友可以一试。 
  •         //既然Text的color是靠TextPaint刷出来的,那么是否可以改变TextPaint的颜色值呢?发现有接口getPaint可以获取到TextPaint, 
  •         //但是设置了color值之后,还是不行,哦,原来在onDraw()函数中,重新设置了颜色值,所以白设了。 
  •         //总而言之,联动刷新颜色是不行滴,只能设一个颜色(对于我目前来讲功能已经是足够了) 哈哈,讲的够详细吧~~ 
  •         ColorStateList mTextColor = mTV.getTextColors(); 
  •          
  •         int color = mTextColor.getColorForState(this.getDrawableState(), 0); 
  •         if (mTV.getCurrentTextColor() != color) { 
  •             mTV.getPaint().setColor(color); 
  • //          mTV.setTextColor(color); 
  •             mTV.invalidate(); 
  •         } 
  •          
  •         //-----------如果有个Button的话就可以在这里设置改变,效果同上,略--------------- 
  • //        Drawable btnDrawable = mBtn.getBackground(); 
  • //      Log.d(TAG, "drawable = " + btnDrawable); 
  • //      if (btnDrawable != null && btnDrawable.isStateful()) { 
  • //          btnDrawable.setState(this.getDrawableState()); 
  • //      } 
  • //       
  • //      ColorStateList mTextColor2 = mBtn.getTextColors(); 
  • //      int color2 = mTextColor2.getColorForState(this.getDrawableState(), 0); 
  • //        if (mBtn.getCurrentTextColor() != color2) { 
  • //          mBtn.setTextColor(color2); 
  • //        } 
  •   
  •     }</span> 
  •  
  •     /**
  •      * 设置图片资源
  •      */  
  •     publicvoid setImgViewResource(int resId) {  
  •         mImg.setImageResource(resId);  
  •     }  
  •      
  •     /**
  •      * 设置图片
  •      */  
  •     publicvoid setImgViewResource(Bitmap bitmap) {  
  •         mImg.setImageBitmap(bitmap);  
  •     }  
  •   
  •     /**
  •      * 设置显示的文字
  •      */  
  •     publicvoid setTextViewText(int resId) {  
  •         mTV.setText(resId);  
  •     }  
  •     /**
  •      * 设置显示的文字
  •      */  
  •     publicvoid setTextViewText(String text) {  
  •         mTV.setText(text);  
  •     }  
  •   

第三步:在value/下面定义一个attrs.xml文件,内容如下: 

  • <?xmlversion="1.0"encoding="utf-8"?> 
  • <resources> 
  •     <declare-styleablename="ImgTextBtn"> 
  •         <attrname="ImgDraw"format="reference"></attr> 
  •         <attrname="ImgDrawWidth"format="dimension"></attr> 
  •         <attrname="ImgDrawHeight"format="dimension"></attr> 
  •         <attrname="ImgDrawMinWidth"format="dimension"></attr> 
  •         <attrname="ImgDrawMinHeight"format="dimension"></attr> 
  •         <attrname="ImgDrawMaxWidth"format="dimension"></attr> 
  •         <attrname="ImgDrawMaxHeight"format="dimension"></attr> 
  •          
  •         <attrname="TVText"format="reference|string"></attr> 
  •         <attrname="TVTextSize"format="dimension"></attr> 
  •         <attrname="TVTextColor"format="reference|color"></attr> 
  •     </declare-styleable> 
  •      
  • </resources> 

第四步:直接在布局中使用

  • <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android" 
  • //CustomAttrs为自定义属性,com.example.testdrawable为包名
  •     xmlns:CustomAttrs="http://schemas.android.com/apk/res/com.example.testdrawable" 
  •     android:layout_width="match_parent" 
  •     android:layout_height="match_parent"> 
  •  
  •     <com.widget.ImgTextBtn 
  •         android:id="@+id/imageTextButton1" 
  •         android:layout_width="match_parent" 
  •         android:layout_height="wrap_content" 
  •         android:orientation="vertical" 
  •         android:layout_above="@+id/textView1" 
  •         android:layout_centerHorizontal="true" 
  •         android:layout_marginBottom="35dp" 
  •         android:background="@drawable/preference_round_rect_light_blue" 
  •         CustomAttrs:TVText="@string/hello_world" 
  •         CustomAttrs:TVTextSize="@dimen/dimens_Padding_normal" 
  •         CustomAttrs:ImgDraw="@drawable/test_btn_selector"> 
  •     </com.widget.ImgTextBtn> 
  •  
  • </RelativeLayout>
原文地址:https://www.cnblogs.com/xiao-xu/p/3438736.html