Android部分开源项目源码分析之---ViewBadge(View 上面动态的自定义的添加view)

前言:

我们有时候,需要在已经设计好的界面上的某一个View上,在事后添加一些view. 如一个消息到达的时候,在切换到消息的那个空间上面,显示一个消息数量的图标。

在开源的项目 https://github.com/jgilfelt/android-viewbadger 中,实现了这样的效果。见下图

                          

在上图的Button 中,上面的红色的提示的图标不是在布局中添加的,而是通过BadgeView 这个类实现的通过原始的控件,动态的添加到这个界面上去的。

BadgeView 源码原理分析:

 部分源码的分析载录.

	public BadgeView(Context context) {
		this(context, (AttributeSet) null, android.R.attr.textViewStyle);
	}
	
	public BadgeView(Context context, AttributeSet attrs) {
		 this(context, attrs, android.R.attr.textViewStyle);
	}
	
	/**
     * Constructor -
     * 
     * create a new BadgeView instance attached to a target {@link android.view.View}.
     *
     * @param context context for this view.
     * @param target the View to attach the badge to.
     */
	public BadgeView(Context context, View target) {
		 this(context, null, android.R.attr.textViewStyle, target, 0);
	}
	
	/**
     * Constructor -
     * 
     * create a new BadgeView instance attached to a target {@link android.widget.TabWidget}
     * tab at a given index.
     *
     * @param context context for this view.
     * @param target the TabWidget to attach the badge to.
     * @param index the position of the tab within the target.
     */
	public BadgeView(Context context, TabWidget target, int index) {
		this(context, null, android.R.attr.textViewStyle, target, index);
	}
	
	public BadgeView(Context context, AttributeSet attrs, int defStyle) {
		this(context, attrs, defStyle, null, 0);
	}
	
	public BadgeView(Context context, AttributeSet attrs, int defStyle, View target, int tabIndex) {
		super(context, attrs, defStyle);
		init(context, target, tabIndex);
	}

	private void init(Context context, View target, int tabIndex) {
		
		this.context = context;
		this.target = target;
		this.targetTabIndex = tabIndex;
		
		// apply defaults
		badgePosition = DEFAULT_POSITION;
		badgeMarginH = dipToPixels(DEFAULT_MARGIN_DIP);
		badgeMarginV = badgeMarginH;
		badgeColor = DEFAULT_BADGE_COLOR;
		
		setTypeface(Typeface.DEFAULT_BOLD);
		int paddingPixels = dipToPixels(DEFAULT_LR_PADDING_DIP);
		setPadding(paddingPixels, 0, paddingPixels, 0);
		setTextColor(DEFAULT_TEXT_COLOR);
		
		fadeIn = new AlphaAnimation(0, 1);
		fadeIn.setInterpolator(new DecelerateInterpolator());
		fadeIn.setDuration(200);

		fadeOut = new AlphaAnimation(1, 0);
		fadeOut.setInterpolator(new AccelerateInterpolator());
		fadeOut.setDuration(200);
		
		isShown = false;
		
		if (this.target != null) {
			applyTo(this.target);
		} else {
			show();
		}
		
	}

	private void applyTo(View target) {
//		1、获取目标源码的布局
		LayoutParams lp = target.getLayoutParams();
		
		ViewParent parent = target.getParent();
		
		
		/**
		 * 新建个容器 存放 原来的target 和 即将添加的 通知信息的TextView
		 */
		FrameLayout container = new FrameLayout(context);
		
		if (target instanceof TabWidget) {
			
			// set target to the relevant tab child container
			target = ((TabWidget) target).getChildTabViewAt(targetTabIndex);
			this.target = target;
			
			((ViewGroup) target).addView(container, 
					new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
			
			this.setVisibility(View.GONE);
			container.addView(this);
			
		} else {
			
			// TODO verify that parent is indeed a ViewGroup
			//获取target View的  所在的容器
			ViewGroup group = (ViewGroup) parent; 
			//获取target View的  所在的容器中的位置
			int index = group.indexOfChild(target);
			//target View的  所在的容器 将 target View 移除
			group.removeView(target);
			// 将新建的 即将包好 target View 和 badge view(在此处是,这个 通知的TextView) 所在的容器,添加到原来target view 所在的位置
			group.addView(container, index, lp);
			
			
			/**
			 * 在自己新建的容器中间 添加target view 和自己 新定义的view.
			 */
			container.addView(target);
			this.setVisibility(View.GONE);
			container.addView(this);
			
			// 界面刷新
			group.invalidate();
			
		}
		
	}
	

自定义的例子:


public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.fragment_main);
		final TextView text = (TextView) findViewById(R.id.test);
		Button button = (Button) findViewById(R.id.button);
		final BadgeView badgeView=new BadgeView(this, text);		
		button.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				badgeView.toggle();
			}
		});
	
	}

	
}

public class BadgeView {
	private Context mContext;
	private View targeView;
	TextView textView;
	public BadgeView(Context mContext, View targeView) {
		super();
		this.mContext = mContext;
		this.targeView = targeView;
		
//		1、获取目标源码的布局
		LayoutParams lParams = targeView.getLayoutParams();
		
		ViewParent targetViewParent = targeView.getParent();
		/**
		 * 新建个容器 存放 原来的target 和 即将添加的 通知信息的TextView
		 */
		FrameLayout container=new FrameLayout(mContext);
		
		//获取target View的  所在的容器
		ViewGroup targetViewParentGroup=(ViewGroup) targetViewParent;
	
		//获取target View的  所在的容器中的位置
		int index=targetViewParentGroup.indexOfChild(targeView);
	
		//target View的  所在的容器 将 target View 移除
		targetViewParentGroup.removeView(targeView);
		
		// 将新建的 即将包好 target View 和 badge view(在此处是,这个 通知的TextView) 所在的容器,添加到原来target view 所在的位置
		targetViewParentGroup.addView(container, index, lParams);
		
		/**
		 * 在自己新建的容器中间 添加target view 和自己 新定义的view.
		 */
		 textView=new TextView(mContext);
		textView.setText("sss");
		textView.setTextColor(Color.RED);
		textView.setVisibility(View.INVISIBLE);
		container.addView(targeView);
		container.addView(textView);
		
		// 界面刷新
		targetViewParentGroup.invalidate();
		
	}
	public void show() {
		textView.setVisibility(View.VISIBLE);
	}
	public void hide() {
		textView.setVisibility(View.INVISIBLE);

	}
	boolean isShow=false;
	public void toggle(){
		if (isShow) {
			hide();
			isShow=false;
		}else {
			show();
			isShow=true;
		}
	}

}

布局文件:
<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.myviewbadger.MainActivity$PlaceholderFragment" >

    <TextView
        android:id="@+id/test"
        android:layout_width="300dp"
        android:layout_height="200dp"
        android:background="@android:color/darker_gray"
        android:text="@string/hello_world" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="ss" />

</RelativeLayout>

源码托管在:https://github.com/dblackde/MyViewBadger


参考:

https://github.com/jgilfelt/android-viewbadger











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值