Android - 自定义View

一、自定义View(ViewGroup)步骤:

  1、extends 某View(ViewGroup)

  2、onMeasure:决定内部(子View)宽与高,以及自己宽与高

  3、onLayout:决定子View位置

  4、onTouchEvent:事件处理

  5、onDraw: 绘图处理

二、自定义属性步骤:

  1、values/attr.xml 【注意】declare-styleable name = 自定义View类名

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="rightPadding" format="dimension" ></attr>
    <declare-styleable name="SlidingView">
        <attr name="rightPadding"></attr>
    </declare-styleable>
</resources>

  2、布局文件中引用:xmlns命名空间 (xmlns:cyz="http://schemas.android.com/apk/res/包名com.example.myview,该包名引用至androidManifest.xml-package"

  3、自定义View构造函数(使用参数最多的那个)中获取自定义属性,【注意】TypeArray 使用后必须进行释放

public SlidingView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);

		// 获取自定义属性
		TypedArray arr = context.getTheme().obtainStyledAttributes(attrs,
				R.styleable.SlidingView, defStyle, 0);
		int n = arr.getIndexCount();
		for (int i = 0; i < n; i++) {
			int attr = arr.getIndex(i);
			switch (attr) {
			case R.styleable.SlidingView_rightPadding:
				mMenuRightPadding = arr.getDimensionPixelSize(attr,
						(int) TypedValue.applyDimension(
								TypedValue.COMPLEX_UNIT_DIP, 50, context
										.getResources().getDisplayMetrics()));
				Log.d(LOG_TAG, "mMenuRightPadding=" + mMenuRightPadding);
				break;
			}
		}
		arr.recycle(); // TypedArray 使用后需要释放

		// 获取屏幕宽度
		WindowManager wm = (WindowManager) getContext().getSystemService(
				Context.WINDOW_SERVICE);
		DisplayMetrics outMetrics = new DisplayMetrics();
		wm.getDefaultDisplay().getMetrics(outMetrics);
		mScreenWidth = outMetrics.widthPixels;
	}

三、动画效果

  1、traslation移动、scale缩放、alpha透明度

  2、rate 1.0-0

      1.0-0.7 -> 0.7+0.3*rate

    0.6-1.0 -> 1.0-0.4*rate

四、模仿QQ侧滑菜单 : 参考慕课网Android-QQ5.0侧滑菜单

  1、自定义View 扩展HorizontalScrollView

      2、menu.xml、content.xml、attr.xml、SlidingMenu.java

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_vertical" >

    <LinearLayout
        android:id="@+id/menu_item_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:gravity="center_vertical"
        android:orientation="horizontal" >

        <ImageView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginLeft="10dp"
            android:contentDescription="@string/menu_first_str"
            android:src="@drawable/img_1" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="@string/menu_first_str"
            android:textColor="#fff"
            android:textSize="18sp" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/menu_item_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/menu_item_1"
        android:layout_marginTop="10dp"
        android:gravity="center_vertical"
        android:orientation="horizontal" >

        <ImageView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginLeft="10dp"
            android:contentDescription="@string/menu_second_str"
            android:src="@drawable/img_2" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="@string/menu_second_str"
            android:textColor="#fff"
            android:textSize="18sp" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/menu_item_3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/menu_item_2"
        android:layout_marginTop="10dp"
        android:gravity="center_vertical"
        android:orientation="horizontal" >

        <ImageView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginLeft="10dp"
            android:contentDescription="@string/menu_third_str"
            android:src="@drawable/img_3" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="@string/menu_third_str"
            android:textColor="#fff"
            android:textSize="18sp" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/menu_item_4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/menu_item_3"
        android:layout_marginTop="10dp"
        android:gravity="center_vertical"
        android:orientation="horizontal" >

        <ImageView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginLeft="10dp"
            android:contentDescription="@string/menu_fourth_str"
            android:src="@drawable/img_4" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="@string/menu_fourth_str"
            android:textColor="#fff"
            android:textSize="18sp" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/menu_item_5"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/menu_item_4"
        android:layout_marginTop="10dp"
        android:gravity="center_vertical"
        android:orientation="horizontal" >

        <ImageView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginLeft="10dp"
            android:contentDescription="@string/menu_fifth_str"
            android:src="@drawable/img_5" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="@string/menu_fifth_str"
            android:textColor="#fff"
            android:textSize="18sp" />
    </LinearLayout>

</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/qq"
    android:orientation="vertical" >
    <Button
        android:id="@+id/btnToggleMenu"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:text="切换菜单"
        android:textColor="#fff" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="rightPadding" format="dimension" ></attr>
    <declare-styleable name="SlidingMenu">
        <attr name="rightPadding"></attr>
    </declare-styleable>
</resources>
package com.example.myview;

import com.nineoldandroids.view.ViewHelper;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;

public class SlidingMenu extends HorizontalScrollView {

	public static final String LOG_TAG = "SlidingMenu";

	private LinearLayout mWrapper;
	private ViewGroup mMenu;
	private ViewGroup mContent;

	private int mScreenWidth;
	private int mMenuWidth;
	private int mMenuRightPadding = 50; // dp; 显示Menu时,Content剩余显示宽度
	private boolean open=false;
	private boolean once = false;

	public SlidingMenu(Context context) {
		this(context, null);
	}

	public SlidingMenu(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);

		// 获取自定义属性
		TypedArray arr = context.getTheme().obtainStyledAttributes(attrs,
				R.styleable.SlidingMenu, defStyle, 0);
		int n = arr.getIndexCount();
		for (int i = 0; i < n; i++) {
			int attr = arr.getIndex(i);
			switch (attr) {
			case R.styleable.SlidingMenu_rightPadding:
				mMenuRightPadding = arr.getDimensionPixelSize(attr,
						(int) TypedValue.applyDimension(
								TypedValue.COMPLEX_UNIT_DIP, 50, context
										.getResources().getDisplayMetrics()));
				Log.d(LOG_TAG, "mMenuRightPadding=" + mMenuRightPadding);
				break;
			}
		}
		arr.recycle(); // TypedArray 使用后需要释放

		// 获取屏幕宽度
		WindowManager wm = (WindowManager) getContext().getSystemService(
				Context.WINDOW_SERVICE);
		DisplayMetrics outMetrics = new DisplayMetrics();
		wm.getDefaultDisplay().getMetrics(outMetrics);
		mScreenWidth = outMetrics.widthPixels;
	}

	/**
	 * 设置子View的宽与高,设置自己的宽与高
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

		if (!once) {
			mWrapper = (LinearLayout) getChildAt(0);
			mMenu = (ViewGroup) mWrapper.getChildAt(0);
			mContent = (ViewGroup) mWrapper.getChildAt(1);

			mMenuWidth = mScreenWidth - mMenuRightPadding;
			mMenu.getLayoutParams().width = mMenuWidth;
			mContent.getLayoutParams().width = mScreenWidth;

			once = true;
		}
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		int action = ev.getAction();
		switch (action) {
		case MotionEvent.ACTION_UP:
			int scrollX = getScrollX();
			if (scrollX >= mMenuWidth / 2) {
				this.smoothScrollTo(mMenuWidth, 0);
				open=false;
			} else {
				this.smoothScrollTo(0, 0);
				open=true;
			}
			return true;
		}
		return super.onTouchEvent(ev);
	}

	/**
	 * 通过设置偏移量,将menu隐藏
	 */
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		if (changed) {
			this.scrollTo(mMenuWidth, 0);
		}
	}
	
	/**
	 * 滚动发生时
	 */
	@Override
	protected void onScrollChanged(int l, int t, int oldl, int oldt)
	{
		super.onScrollChanged(l, t, oldl, oldt);
		
		//动画效果:抽屉式Menu, 右侧Content缩放
		//动画参照物:scrollX 
		
		float rate=l*1.0f/mMenuWidth; //1~0; 梯度
		
		//Menu动画:
		float menu_translationX= 0.8f*l;   
		float menu_scale= 1.0f-0.3f*rate;         //0.7~1
		float menu_alpha=1.0f-0.4f*rate;          //0.6~1
		//content动画:
		float content_scale=0.7f+0.3f*rate;       //1~0.7

		// 调用属性动画,设置TranslationX
		ViewHelper.setTranslationX(mMenu, menu_translationX);
		ViewHelper.setScaleX(mMenu, menu_scale);
		ViewHelper.setScaleY(mMenu, menu_scale);
		ViewHelper.setAlpha(mMenu, menu_alpha);
		// 设置content的缩放的中心点
		ViewHelper.setPivotX(mContent, 0);
		ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);
		ViewHelper.setScaleX(mContent, content_scale);
		ViewHelper.setScaleY(mContent, content_scale);
	}
	
	public void openMenu(){
		if(open) return;
		this.smoothScrollTo(0, 0);
		open=true;
	}
	
	public void closeMenu(){
		if(!open) return;
		this.smoothScrollTo(mMenuWidth, 0);
		open=false;
	}
	
	public void toggleMenu(){
		if(open){
			closeMenu();
		}else{
			openMenu();
		}
	}
}

  

  

  

 

  

posted @ 2016-01-19 16:22  chenyizh  阅读(167)  评论(0)    收藏  举报