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();
}
}
}
浙公网安备 33010602011771号