自定义ViewGroup
1.onMeasure
决定内部子View的宽和高,以及自己的宽和高
2.onLayout
决定子View的放置的位置
3.onTouchEvent
代码实例(代码实现的是侧滑实例):
package com.example.hujiaxuan.spinner2;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
/**
* Created by hujiaxuan on 2014/11/30.
*/
public class SlidingMenu extends HorizontalScrollView {
private int mScreenWidth;
private LinearLayout mWrapper;
private ViewGroup mMenu;
private ViewGroup mContent;
private int mMenuRightPadding=200;
private int mMenuWidth;
private boolean once;
/**
*
* @param context
* @param attrs
* @param defStyle
*/
public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//获取定义的属性;
TypedArray a=context.getTheme().obtainStyledAttributes(attrs,R.styleable.SlidingMenu,defStyle,0);
int n=a.getIndexCount();
for(int i=0;i<n;i++){
int attr=a.getIndex(i);
switch(attr){
case R.styleable.SlidingMenu_rightPadding:
mMenuRightPadding=a.getDimensionPixelSize(attr,
(int)TypedValue.applyDimension
(TypedValue.COMPLEX_UNIT_DIP,50,context.getResources().getDisplayMetrics()));
break;
}
}
a.recycle();
WindowManager wm=(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics=new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth=outMetrics.widthPixels;//获取屏幕宽度
}
public SlidingMenu(Context context) {
this(context, null);
}
public SlidingMenu(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
//自定义ViewGroup
//决定内部View(子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=mMenu.getLayoutParams().width=mScreenWidth-mMenuRightPadding;
mContent.getLayoutParams().width=mScreenWidth;
once=true;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
//决定子View的放置位置
@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
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);//将菜单完全显示
System.out.println("show");
}else{
this.smoothScrollTo(0,0);
}
return true;
}
return super.onTouchEvent(ev);
}
}
MyActivity.java文件:
package com.example.hujiaxuan.spinner2;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
public class MyActivity extends Activity {
private SlidingMenu mLeftMenu;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_my);
mLeftMenu=(SlidingMenu)findViewById(R.id.id_menu);
}
public void troggleMenu(View view){
mLeftMenu.toggle();
}
}
自定义属性的三个步骤
1.书写Xml文件 Vlaues/attrs.xml
2.在布局文件中使用,特别要注意xmlns
3.在构造方法中(三个参数的构造方法)获取我们要取得的值。
代码实例:
Values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="rightPadding" format="dimension"></attr>
<declare-styleable name="SlidingMenu">
<attr name="rightPadding" format="dimension"></attr>
</declare-styleable>
</resources>
activity_my.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
<span style="color:#ff0000;">xmlns:vensli="http://schemas.android.com/apk/res/com.example.hujiaxuan.spinner2"</span>
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.example.hujiaxuan.spinner2.SlidingMenu
android:layout_width="match_parent"
android:layout_height="match_parent"
<span style="color:#ff0000;">vensli:rightPadding="100dp"</span>>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<include layout="@layout/left_menu"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/img_frame_background"></LinearLayout>
</LinearLayout>
</com.example.hujiaxuan.spinner2.SlidingMenu>
</RelativeLayout>
红色代码标注的是自定义属性
最后,给大家介绍下View和ViewGroup最重要的几个方法——
protected void onDraw(Canvas canvas):View类中用于重绘的方法,这个方法是所有View、ViewGroup及其派生类都具有的方法,也是Android UI绘制最重要的方法。开发者可重载该方法,并在重载的方法内部基于参数canvas绘制自己的各种图形、图像效果。
protected void onLayout(boolean changed, int left, int top, int right, int bottom):View类中布局发生改变时会调用的方法,这个方法是所有View、ViewGroup及其派生类都具有的方法,重载该类可以在布局发生改变时作定制处理,这在实现一些特效时非常有用。
protected void dispatchDraw(Canvas canvas):ViewGroup类及其派生类具有的方法,这个方法主要用于控制子View的绘制分发,重载该方法可改变子View的绘制,进而实现一些复杂的视效,典型的例子可参见Launcher模块Workspace的dispatchDraw重载。
protected boolean drawChild(Canvas canvas, View child, long drawingTime)):ViewGroup类及其派生类具有的方法,这个方法直接控制绘制某局具体的子view,重载该方法可控制具体某个具体子View。