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











發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章