Android自己定義組件系列【3】——自己定義ViewGroup實現側滑

來源:互聯網
上載者:User

標籤:android   style   class   blog   c   code   

有關自己定義ViewGroup的文章已經非常多了,我為什麼寫這篇文章,對於剛開始學習的人或者對自己定義組件比較生疏的朋友儘管能夠拿來主義的用了,可是要一步一步的實現和瞭解當中的過程和原理才幹真真脫離別人的代碼,舉一反三卻不easy,非常多博主事實上不願意一步一步的去寫,這樣非常耗時,可是假設能對讀者有協助,能從這篇文章中學會自己定義組件就達到我的目的了。

第一步:搭建架構來實現一個3/5和2/5分屏的介面,效果例如以下:


最外層是一個自己定義的ViewGroup布局檔案例如以下:

package com.example.testscrollto;import android.content.Context;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;import android.view.View.MeasureSpec;public class MyScrollView extends ViewGroup{private int mWidth;private int mHeight;private float mMenuWeight = 3.0f / 5; //菜單介面比例private View mMenuView;   //菜單介面private View mPriView;  //內容介面public MyScrollView(Context context, AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {System.out.println("運行了onLayout");mMenuView.layout(0, 0, (int)(mWidth * mMenuWeight), mHeight);mPriView.layout((int)(mWidth * mMenuWeight), 0, mWidth, mHeight);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {System.out.println("運行了onMeasure");super.onMeasure(widthMeasureSpec, heightMeasureSpec);/* * onMeasure傳入的兩個參數是由上一層控制項傳入的大小,有多種情況,重寫該方法時須要對計算控制項的實際大小, * 然後調用setMeasuredDimension(int, int)設定實際大小。 * onMeasure傳入的widthMeasureSpec和heightMeasureSpec不是一般的尺寸數值,而是將模式和尺寸組合在一起的數值。 * 我們須要通過int mode = MeasureSpec.getMode(widthMeasureSpec)得到模式, * 用int size = MeasureSpec.getSize(widthMeasureSpec)得到尺寸。 * mode共同擁有三種情況,取值分別為MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, MeasureSpec.AT_MOST。 * MeasureSpec.EXACTLY是精確尺寸,當我們將控制項的layout_width或layout_height指定為詳細數值時如andorid:layout_width="50dip",或者為FILL_PARENT是,都是控制項大小已經確定的情況,都是精確尺寸。 * MeasureSpec.AT_MOST是最大尺寸,當控制項的layout_width或layout_height指定為WRAP_CONTENT時,控制項大小一般隨著控制項的子空間或內容進行變化,此時控制項尺寸僅僅要不超過父控制項同意的最大尺寸就可以。因此,此時的mode是AT_MOST,size給出了父控制項同意的最大尺寸。 * MeasureSpec.UNSPECIFIED是未指定尺寸,這樣的情況不多,一般都是父控制項是AdapterView,通過measure方法傳入的模式。 */mWidth = MeasureSpec.getSize(widthMeasureSpec);  //擷取MyScrollView的寬度mHeight = MeasureSpec.getSize(heightMeasureSpec); //擷取MyScrollView的高度}/**設定右滑的菜單View*/public void setMenu(View menu){mMenuView = menu;addView(mMenuView);}/** * 設定主介面View */public void setPrimary(View primary){mPriView = primary;addView(mPriView);}}
第二步:按須要設定介面位置

@Overrideprotected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {mMenuView.layout(-(int)(mWidth * mMenuWeight), 0, 0, mHeight);mPriView.layout(0, 0, mWidth, mHeight);}

第三步:實現左右滑動

package com.example.testscrollto;import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.Scroller;public class MyScrollView extends ViewGroup{private Context mContext;private int mWidth;private int mHeight;private float mMenuWeight = 3.0f / 5; //菜單介面比例private View mMenuView;   //菜單介面private View mPriView;  //內容介面private boolean mIsShowMenu;private Scroller mScroller;public MyScrollView(Context context, AttributeSet attrs) {super(context, attrs);mContext = context;mScroller = new Scroller(mContext);}@Overrideprotected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {mMenuView.layout(-(int)(mWidth * mMenuWeight), 0, 0, mHeight);mPriView.layout(0, 0, mWidth, mHeight);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = MeasureSpec.getSize(widthMeasureSpec);  //擷取MyScrollView的寬度mHeight = MeasureSpec.getSize(heightMeasureSpec); //擷取MyScrollView的高度}/**設定右滑的菜單View*/public void setMenu(View menu){mMenuView = menu;addView(mMenuView);}/** * 設定主介面View */public void setPrimary(View primary){mPriView = primary;addView(mPriView);}private float mDownX;@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:System.out.println("ACTION_DOWN");mDownX = x;          //記錄按下時的x座標break;case MotionEvent.ACTION_UP:System.out.println("ACTION_UP");int dis = (int) (x - mDownX);   //滑動的距離if(Math.abs(dis) > (mWidth * mMenuWeight / 2)){if(dis > 0){          //假設>0則是向右滑動showMenu();}else{  //假設<0則是向左滑動hideMenu();}}break;default:break;}return true;}@Overridepublic void computeScroll() {super.computeScroll();if(mScroller.computeScrollOffset()){scrollTo(mScroller.getCurrX(), mScroller.getCurrY());postInvalidate();}}public boolean isShowMenu(){return mIsShowMenu;}public void showMenu(){ if(mIsShowMenu){ return; } mIsShowMenu = true;  //標記菜單已經顯示 int dx = (int)(mWidth * mMenuWeight);  //滑動到目標位置的距離 mScroller.startScroll(getScrollX(), 0, -dx, 0, 500); invalidate();}public void hideMenu(){if(!mIsShowMenu){return;}mIsShowMenu = false;int dx = (int)(mWidth * mMenuWeight);mScroller.startScroll(getScrollX(), 0, dx, 0, 500);invalidate();} }
從上面代碼中能夠看到以下兩句代碼觸發computeScroll()方法

mScroller.startScroll(getScrollX(), 0, -dx, 0, 500);invalidate();
第四步:加入表單狀態切換監聽介面
public interface OnMenuChangedListener{ public void onChanged(boolean isShow);}public void setOnMenuChangedListener(OnMenuChangedListener listener){mListener = listener;}
將showMenu()方法和hideMenu()方法改動例如以下:

public void showMenu(){ if(mIsShowMenu){ return; } mIsShowMenu = true; int dx = (int)(mWidth * mMenuWeight); mScroller.startScroll(getScrollX(), 0, -dx, 0, 500); if(mListener != null){ mListener.onChanged(mIsShowMenu); } invalidate();}public void hideMenu(){if(!mIsShowMenu){return;}mIsShowMenu = false;int dx = (int)(mWidth * mMenuWeight);mScroller.startScroll(getScrollX(), 0, dx, 0, 500); if(mListener != null){ mListener.onChanged(mIsShowMenu); } invalidate();}
在MainActivity中加入監聽

mScrollView.setOnMenuChangedListener(new OnMenuChangedListener() {@Overridepublic void onChanged(boolean isShow) {System.out.println("表單切換了一次");}});
第五步:依據詳細業務及需求實現菜單列表及介面(直接貼出代碼)

MainActivity.java

package com.example.testrefreshview;import android.app.Activity;import android.graphics.Color;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.ArrayAdapter;import android.widget.Button;import android.widget.ListView;import com.example.testrefreshview.RightScrollView.OnMenuChangedListener;/** * 測試具有右滑菜單功能的ViewGroup,RigthScrollView *@author Lqh */public class MainActivity extends Activity {private RightScrollView mRightScrollView;private Button mShowMenuBtn;private ListView mMenuList;private ArrayAdapter<String> mAdapter;private String[] menus = {"附近的人", "我的資料", "設定", "遊戲", "即時聊天"};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.rightscrollview_test);mRightScrollView = (RightScrollView)findViewById(R.id.rightscrollview);final View menu = getLayoutInflater().inflate(R.layout.rightscrollview_menu, null);final View primary = getLayoutInflater().inflate(R.layout.rightscrollview_primary, null);mMenuList = (ListView) menu.findViewById(R.id.list_right_menu);mShowMenuBtn = (Button) primary.findViewById(R.id.btn_showmenu);mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, menus);mMenuList.setAdapter(mAdapter);mShowMenuBtn.setOnClickListener(new OnClickListener() {public void onClick(View v) {if(mRightScrollView.isShowMenu()){mRightScrollView.hideMenu();}else{mRightScrollView.showMenu();}}});mRightScrollView.setOnMenuChangedListener(new OnMenuChangedListener() {public void onChanged(boolean isShow) {if(isShow){mShowMenuBtn.setText("隱藏菜單");}else{mShowMenuBtn.setText("顯示菜單");}}});mRightScrollView.setMenu(menu);mRightScrollView.setPrimary(primary);mMenuList.setOnItemClickListener(new OnItemClickListener() {public void onItemClick(AdapterView<?> parent, View view, int position, long id) {switch(position){case 0:primary.setBackgroundColor(Color.CYAN);break;case 1:primary.setBackgroundColor(Color.BLUE);break;case 2:primary.setBackgroundColor(Color.GRAY);break;case 3:primary.setBackgroundColor(Color.MAGENTA);break;case 4:primary.setBackgroundColor(Color.YELLOW);break;}mRightScrollView.hideMenu();}});}}
RightScrollView.java

package com.example.testrefreshview;import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.Scroller;/** * 具有右滑菜單的ViewGroup,相似於Facebook的主介面 * @author Lqh */public class RightScrollView extends ViewGroup {private Context mContext;private Scroller mScroller;private View mMenuView;private View mPriView;private int mWidth;private int mHeight;private boolean mIsShowMenu;private float mMenuWeight = 3.0f / 5;private OnMenuChangedListener mListener;public RightScrollView(Context context) {this(context, null);}public RightScrollView(Context context, AttributeSet attrs) {super(context, attrs);mContext = context;mScroller = new Scroller(mContext);}/**設定右滑的菜單View*/public void setMenu(View menu){mMenuView = menu;addView(mMenuView);}/** * 設定主介面View */public void setPrimary(View primary){mPriView = primary;addView(mPriView);}public boolean isShowMenu(){return mIsShowMenu;}public void setOnMenuChangedListener(OnMenuChangedListener listener){mListener = listener;}public void showMenu(){ if(mIsShowMenu){ return; } mIsShowMenu = true; int dx = (int)(mWidth * mMenuWeight); mScroller.startScroll(getScrollX(), 0, -dx, 0, 500); if(mListener != null){ mListener.onChanged(mIsShowMenu); } invalidate();}public void hideMenu(){if(!mIsShowMenu){return;}mIsShowMenu = false;int dx = (int)(mWidth * mMenuWeight);mScroller.startScroll(getScrollX(), 0, dx, 0, 500); if(mListener != null){ mListener.onChanged(mIsShowMenu); } invalidate();}private float mDownX;@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX();switch(event.getAction()){case MotionEvent.ACTION_DOWN:mDownX = x;break;case MotionEvent.ACTION_UP:int dis = (int) (x - mDownX);if(Math.abs(dis) > (mWidth * mMenuWeight / 2)){if(dis > 0){showMenu();}else{hideMenu();}}break;}return true;} @Overridepublic void computeScroll() {super.computeScroll();if(mScroller.computeScrollOffset()){scrollTo(mScroller.getCurrX(), mScroller.getCurrY());postInvalidate();}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {mWidth = MeasureSpec.getSize(widthMeasureSpec);mHeight = MeasureSpec.getSize(heightMeasureSpec);setMeasuredDimension(mWidth, mHeight);int widthSpec = MeasureSpec.makeMeasureSpec((int)(mWidth * mMenuWeight), MeasureSpec.EXACTLY);int heightSpec = MeasureSpec.makeMeasureSpec(mHeight, MeasureSpec.EXACTLY);mMenuView.measure(widthSpec, heightSpec);widthSpec = MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY);mPriView.measure(widthSpec, heightSpec);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {mMenuView.layout(-(int)(mWidth * mMenuWeight), 0, 0, mHeight);mPriView.layout(0, 0, mWidth, mHeight);} public interface OnMenuChangedListener{ public void onChanged(boolean isShow); } }
運行效果:



源碼下載:http://download.csdn.net/detail/lxq_xsyu/7231677

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.