一步一步实现Android自定义组合View
Android自定义View之组合View
前序
最近在开发一款电商类B端APP,比较忙,现在最新版本要上线了。刚好年底才有时间停下来梳理一下自己写过的东西,顺便分享一些出来,抛砖引玉,还请大家不吝赐教。
设计图UI效果
我们这里要介绍的就是后面三块的UI效果实现。可以看到这几个块都是类似的,但是如果要一个一个用布局写出来,不仅工作量大,而且还会造成XML文件代码冗余、文件臃肿。显然,我们可以通过自定义View来实现一个块的效果,然后在需要的地方include进来就好了,代码也简洁好看。
实现思路
最外层布局采用LinearLayout,图片部分和底部文字部分就可以使用android:layout_weight来控制显示比例。文字部分也可以使用LinearLayout来布局,设置android:gravity=”center”就好,里面的TextView就不赘述了。
动手实现
继承LinearLayout实现外部轮廓
先写好XML布局文件,调整好要实现的效果。下面是XML代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recommended_item_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/item_bound"
android:orientation="vertical"
android:clickable="true" >
<com.personal.views.RemoteImageView
android:id="@+id/recommended_item_front_cover"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="2.5"
android:scaleType="centerCrop"
android:src="@drawable/default_loading" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical" >
<TextView
android:id="@+id/recommended_item_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center"
android:textColor="@color/v123_light_gray"
android:textSize="15dip" />
<LinearLayout
android:id="@+id/recommended_item_price_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="3dip"
android:orientation="horizontal" >
<TextView
android:id="@+id/recommended_item_newprice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/red"
android:textSize="15dp" />
<TextView
android:id="@+id/recommended_item_oldprice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dip"
android:textColor="@color/v123_light_gray"
android:textSize="12dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
新建[Java][6]代码文件RecommendedItem.java继承LinearLayout,把上面的布局文件使用LayoutInflater加载进来。
public class RecommendedItem extends LinearLayout {
public static final String TAG = RecommendedItem .class.getSimpleName();
private Context mContext;
private boolean isDataSet = false;
private float titleTextSize, newPriceTextSize, oldPriceTextSize;
private RemoteImageView mItemCover;
private TextView mItemTitle, mItemNewPrice, mItemOldPrice;
private LinearLayout mPriceLayout, mRootLayout;
public RecommendedItem (Context context) {
super(context);
init(context, null);
}
public RecommendedItem (Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
@SuppressLint("NewApi")
public RecommendedItem (Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
mContext = context; LayoutInflater.from(context).inflate(R.layout.v2_recommended_item, this, true);
}
定义各种需要的属性
在values文件夹下新建attrs.xml文件,添加我们需要的View属性。
<declare-styleable name="RecommendedItem">
<attr name="title_textsize" format="dimension"/>
<attr name="newPrice_textsize" format="dimension"/>
<attr name="oldPrice_textsize" format="dimension"/>
</declare-styleable>
然后我们就可以在XML文件中引用这些属性了,在RecommendedItem类的init方法中获取我们在XML文件中写的这些属性的值。
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.RecommendedItem);
this.titleTextSize = array.getDimension(R.styleable.RecommendedItem_title_textsize, 15);
this.newPriceTextSize = array.getDimension(R.styleable.RecommendedItem_newPrice_textsize, 15);
this.oldPriceTextSize = array.getDimension(R.styleable.RecommendedItem_oldPrice_textsize, 12);
array.recycle(); // 一定要调用,否则这次的设定会对下次的使用造成影响
Log.d(TAG, "this.titleTextSize=" + this.titleTextSize);
Log.d(TAG, "this.newPriceTextSize=" + this.newPriceTextSize);
Log.d(TAG, "this.oldPriceTextSize=" + this.oldPriceTextSize);
初始化View
@Override
protected void onFinishInflate() {
super.onFinishInflate();
this.mItemCover = (RemoteImageView) this.findViewById(R.id.recommended_item_front_cover);
this.mItemTitle = (TextView) this.findViewById(R.id.recommended_item_title);
this.mItemNewPrice = (TextView) this.findViewById(R.id.recommended_item_newprice);
this.mItemOldPrice = (TextView) this.findViewById(R.id.recommended_item_oldprice);
this.mPriceLayout = (LinearLayout) this.findViewById(R.id.recommended_item_price_layout);
this.mRootLayout = (LinearLayout) this.findViewById(R.id.recommended_item_root);
this.mItemTitle.setTextSize(this.titleTextSize);
this.mItemNewPrice.setTextSize(this.newPriceTextSize);
this.mItemOldPrice.setTextSize(this.oldPriceTextSize);
}
添加一些必要的接口方法
自定义的View给外部使用提供接口,动态修改它的属性,实现我们想要的显示效果。
// 设置点击事件监听器
public void setOnClickListener(OnClickListener listener) {
if(listener != null) {
this.mRootLayout.setOnClickListener(listener);
}
}
public void setItemCover(int resId) {
this.mItemCover.setImageResource(resId);
}
public void setItemCover(String url) {
this.mItemCover.setImageUrl(url);
}
public void setItemCover(Bitmap bitmap, boolean need2Recycle) {
this.mItemCover.setImageBitmap(bitmap);
if(need2Recycle) {
if(bitmap != null) {
bitmap = null;
System.gc();
}
}
}
public void loadItemCover(String remoteUrl) {
UILManager.displayImage(remoteUrl, this.mItemCover, UILManager.optionsPicsPreview);
}
public void setItemTitle(String title) {
this.mItemTitle.setText(title);
}
public String getItemTitle() {
if(!TextUtils.isEmpty(this.mItemTitle.getText())) {
return this.mItemTitle.getText().toString();
}
return null;
}
public void setItemNewPrice(String newPrice) {
this.mItemNewPrice.setText(String.format(mContext.getString(R.string.recommended_item_price_format), newPrice));
}
public void setItemOldPrice(String oldPrice) {
this.mItemOldPrice.setText(String.format(mContext.getString(R.string.recommended_item_price_format), oldPrice));
this.mItemOldPrice.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);
}
public void setPriceLayoutVisible(boolean visible) {
if(!visible) {
this.mPriceLayout.setVisibility(View.GONE);
} else {
this.mPriceLayout.setVisibility(View.VISIBLE);
}
}
public boolean isDataSet() {
return isDataSet;
}
public void setDataSet(boolean isDataSet) {
this.isDataSet = isDataSet;
if(isDataSet && this.mPriceLayout.getVisibility() == View.GONE)
this.mPriceLayout.setVisibility(View.VISIBLE);
}
public void clearView() {
this.mItemCover.setImageResource(R.drawable.default_loading);
this.mItemTitle.setText(null);
this.mPriceLayout.setVisibility(View.GONE);
}
自定义View完成
至此,我们根据UI设计图实现的自定义View就完成,可以方便地在其他任何布局文件中使用了。
自定义View的引用
<com.personal.views.RecommendedItem
android:id="@+id/recommended_spike_1"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_marginLeft="10dip"
android:layout_weight="1" />
实现效果图
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。