編輯:關於android開發
如下是布局文件 主要是一個PullToRefreshView內包含一個Scrollview 在滑動面中放一個GridView 底部放個按鈕 當點擊時會返回手機頂部
其中的滑動PullToRefreshView是我從別人的代碼直接拿來的
<?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="#eee" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="15dp" android:gravity="center_vertical" android:paddingBottom="4dp" android:paddingTop="5dp" android:text="所有產品" android:textSize="15sp" /> <View android:layout_width="fill_parent" android:layout_height="1dp" android:background="@android:color/white" /> <org.xml.demo.PullToRefreshView android:id="@+id/pulltorefresh" android:layout_width="match_parent" android:layout_height="wrap_content" > <ScrollView android:id="@+id/sc_view_id" android:layout_width="match_parent" android:layout_height="wrap_content" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <org.xml.demo.MyGridView android:id="@+id/product" android:layout_width="match_parent" android:layout_height="wrap_content" android:horizontalSpacing="5dp" android:numColumns="2" android:paddingBottom="10dp" android:paddingLeft="7dp" android:paddingRight="7dp" android:paddingTop="5dp" android:verticalSpacing="8dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:layout_marginTop="10dp" android:background="@android:color/white" android:orientation="horizontal" android:padding="5dp" > <TextView android:id="@+id/tv_backtop" android:layout_width="match_parent" android:layout_height="match_parent" android:drawableRight="@drawable/back_top" android:gravity="center" android:text="點擊 將返回頂部" android:paddingRight="10dp" android:textColor="@android:color/black" android:textSize="14sp" /> </LinearLayout> </LinearLayout> </ScrollView> </org.xml.demo.PullToRefreshView> </LinearLayout>
主代碼是
package org.xml.demo; import java.text.DateFormat; import java.util.Date; import org.xml.demo.PullToRefreshView.OnFooterRefreshListener; import org.xml.demo.PullToRefreshView.OnHeaderRefreshListener; import ogg.huanxin.huadong.R; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.Window; import android.widget.AdapterView; import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; public class MyProducte extends Activity implements OnHeaderRefreshListener, OnFooterRefreshListener { // private GridView productGridView; /** 定義產品 */ private MyGridView product_gridView; /** 產品的適配器 */ private ProducteGridAdapter producteGridAdapter; /** 下拉刷新 */ private PullToRefreshView pullToRefreshView; /** 點擊返回到頂部 */ private TextView tv_backtop; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //取消標題欄 requestWindowFeature(Window.FEATURE_NO_TITLE); // 定義布局變量 super.setContentView(R.layout.home_product); pullToRefreshView = (PullToRefreshView) super .findViewById(R.id.pulltorefresh); //頭部刷新 pullToRefreshView.setOnHeaderRefreshListener(this); //尾部刷新 pullToRefreshView.setOnFooterRefreshListener(this); pullToRefreshView.setLastUpdated(new Date().toLocaleString()); // 取得控件 product_gridView = (MyGridView) super.findViewById(R.id.product); tv_backtop = (TextView) super.findViewById(R.id.tv_backtop); // 設置適配器 producteGridAdapter = new ProducteGridAdapter(this); product_gridView.setAdapter(producteGridAdapter); // product_gridView.setOnItemClickListener(new ItemClickListener()); product_gridView.setOnItemClickListener(new ItemClickListener()); // tv_backtop的監聽器 tv_backtop.setOnClickListener(new android.view.View.OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub product_gridView.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub MyProducte.this.findViewById(R.id.sc_view_id).scrollTo( 0, 0); } }); } }); } private class ItemClickListener implements OnItemClickListener { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub } } @Override public void onHeaderRefresh(PullToRefreshView view) { // TODO Auto-generated method stub pullToRefreshView.postDelayed(new Runnable() { @Override public void run() { // TODO Auto-generated method stub Date date = new Date(); DateFormat ddf = DateFormat.getDateInstance(); String day = ddf.format(date); DateFormat ddy = DateFormat.getTimeInstance(); String timeString = ddy.format(date); DateFormat ddty = DateFormat.getDateTimeInstance(); String shjian = ddty.format(date); System.out.println(day + "----" + timeString + "--------" + shjian); // pullToRefreshView.onHeaderRefreshComplete("更新為"+new // Date().toLocaleString()); pullToRefreshView.onHeaderRefreshComplete("更新為" + timeString); } }, 1000); } @Override public void onFooterRefresh(PullToRefreshView view) { // TODO Auto-generated method stub pullToRefreshView.onFooterRefreshComplete(); } }
其中的PullToRefreshView的代碼是也是別人的全代碼
package org.xml.demo; import ogg.huanxin.huadong.R; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.LinearInterpolator; import android.view.animation.RotateAnimation; import android.widget.AdapterView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.ScrollView; import android.widget.TextView; public class PullToRefreshView extends LinearLayout { // private static final String TAG = "PullToRefreshView"; // refresh states private static final int PULL_TO_REFRESH = 2; private static final int RELEASE_TO_REFRESH = 3; private static final int REFRESHING = 4; // pull state private static final int PULL_UP_STATE = 0; private static final int PULL_DOWN_STATE = 1; /** * last y */ private int mLastMotionY; /** * lock */ // private boolean mLock; /** * header view */ private View mHeaderView; /** * footer view */ private View mFooterView; /** * list or grid */ private AdapterView<?> mAdapterView; /** * scrollview */ private ScrollView mScrollView; /** * header view height */ private int mHeaderViewHeight; /** * footer view height */ private int mFooterViewHeight; /** * header view image */ private ImageView mHeaderImageView; /** * footer view image */ private ImageView mFooterImageView; /** * header tip text */ private TextView mHeaderTextView; /** * footer tip text */ private TextView mFooterTextView; /** * header refresh time */ private TextView mHeaderUpdateTextView; /** * footer refresh time */ // private TextView mFooterUpdateTextView; /** * header progress bar */ private ProgressBar mHeaderProgressBar; /** * footer progress bar */ private ProgressBar mFooterProgressBar; /** * layout inflater */ private LayoutInflater mInflater; /** * header view current state */ private int mHeaderState; /** * footer view current state */ private int mFooterState; /** * pull state,pull up or pull down;PULL_UP_STATE or PULL_DOWN_STATE */ private int mPullState; /** * 變為向下的箭頭,改變箭頭方向 */ private RotateAnimation mFlipAnimation; /** * 變為逆向的箭頭,旋轉 */ private RotateAnimation mReverseFlipAnimation; /** * footer refresh listener */ private OnFooterRefreshListener mOnFooterRefreshListener; /** * footer refresh listener */ private OnHeaderRefreshListener mOnHeaderRefreshListener; /** * last update time */ // private String mLastUpdateTime; public PullToRefreshView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public PullToRefreshView(Context context) { super(context); init(); } /** * init * * @param context */ private void init() { // 需要設置成vertical setOrientation(LinearLayout.VERTICAL); // Load all of the animations we need in code rather than through XML mFlipAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); mFlipAnimation.setInterpolator(new LinearInterpolator()); mFlipAnimation.setDuration(250); mFlipAnimation.setFillAfter(true); mReverseFlipAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); mReverseFlipAnimation.setInterpolator(new LinearInterpolator()); mReverseFlipAnimation.setDuration(250); mReverseFlipAnimation.setFillAfter(true); mInflater = LayoutInflater.from(getContext()); // header view 在此添加,保證是第一個添加到linearlayout的最上端 addHeaderView(); } private void addHeaderView() { // header view mHeaderView = mInflater.inflate(R.layout.refresh_header, this, false); mHeaderImageView = (ImageView) mHeaderView .findViewById(R.id.pull_to_refresh_image); mHeaderTextView = (TextView) mHeaderView .findViewById(R.id.pull_to_refresh_text); mHeaderUpdateTextView = (TextView) mHeaderView .findViewById(R.id.pull_to_refresh_updated_at); mHeaderProgressBar = (ProgressBar) mHeaderView .findViewById(R.id.pull_to_refresh_progress); // header layout measureView(mHeaderView); mHeaderViewHeight = mHeaderView.getMeasuredHeight(); LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mHeaderViewHeight); // 設置topMargin的值為負的header View高度,即將其隱藏在最上方 params.topMargin = -(mHeaderViewHeight); // mHeaderView.setLayoutParams(params1); addView(mHeaderView, params); } private void addFooterView() { // footer view mFooterView = mInflater.inflate(R.layout.refresh_footer, this, false); mFooterImageView = (ImageView) mFooterView .findViewById(R.id.pull_to_load_image); mFooterTextView = (TextView) mFooterView .findViewById(R.id.pull_to_load_text); mFooterProgressBar = (ProgressBar) mFooterView .findViewById(R.id.pull_to_load_progress); // footer layout measureView(mFooterView); mFooterViewHeight = mFooterView.getMeasuredHeight(); LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mFooterViewHeight); // int top = getHeight(); // params.topMargin // =getHeight();//在這裡getHeight()==0,但在onInterceptTouchEvent()方法裡getHeight()已經有值了,不再是0; // getHeight()什麼時候會賦值,稍候再研究一下 // 由於是線性布局可以直接添加,只要AdapterView的高度是MATCH_PARENT,那麼footer view就會被添加到最後,並隱藏 addView(mFooterView, params); } @Override protected void onFinishInflate() { super.onFinishInflate(); // footer view 在此添加保證添加到linearlayout中的最後 addFooterView(); initContentAdapterView(); } /** * init AdapterView like ListView,GridView and so on;or init ScrollView * */ private void initContentAdapterView() { int count = getChildCount(); if (count < 3) { throw new IllegalArgumentException( "This layout must contain 3 child views,and AdapterView or ScrollView must in the second position!"); } View view = null; for (int i = 0; i < count - 1; ++i) { view = getChildAt(i); if (view instanceof AdapterView<?>) { mAdapterView = (AdapterView<?>) view; } if (view instanceof ScrollView) { // finish later mScrollView = (ScrollView) view; } } if (mAdapterView == null && mScrollView == null) { throw new IllegalArgumentException( "must contain a AdapterView or ScrollView in this layout!"); } } private void measureView(View child) { ViewGroup.LayoutParams p = child.getLayoutParams(); if (p == null) { p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width); int lpHeight = p.height; int childHeightSpec; if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); } @Override public boolean onInterceptTouchEvent(MotionEvent e) { int y = (int) e.getRawY(); switch (e.getAction()) { case MotionEvent.ACTION_DOWN: // 首先攔截down事件,記錄y坐標 mLastMotionY = y; break; case MotionEvent.ACTION_MOVE: // deltaY > 0 是向下運動,< 0是向上運動 int deltaY = y - mLastMotionY; if (isRefreshViewScroll(deltaY)) { return true; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: break; } return false; } /* * 如果在onInterceptTouchEvent()方法中沒有攔截(即onInterceptTouchEvent()方法中 return * false)則由PullToRefreshView 的子View來處理;否則由下面的方法來處理(即由PullToRefreshView自己來處理) */ @Override public boolean onTouchEvent(MotionEvent event) { // if (mLock) { // return true; // } int y = (int) event.getRawY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // onInterceptTouchEvent已經記錄 // mLastMotionY = y; break; case MotionEvent.ACTION_MOVE: int deltaY = y - mLastMotionY; if (mPullState == PULL_DOWN_STATE) {// 執行下拉 headerPrepareToRefresh(deltaY); // setHeaderPadding(-mHeaderViewHeight); } else if (mPullState == PULL_UP_STATE) {// 執行上拉 footerPrepareToRefresh(deltaY); } mLastMotionY = y; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: int topMargin = getHeaderTopMargin(); if (mPullState == PULL_DOWN_STATE) { if (topMargin >= 0) { // 開始刷新 headerRefreshing(); } else { // 還沒有執行刷新,重新隱藏 setHeaderTopMargin(-mHeaderViewHeight); } } else if (mPullState == PULL_UP_STATE) { if (Math.abs(topMargin) >= mHeaderViewHeight + mFooterViewHeight) { // 開始執行footer 刷新 footerRefreshing(); } else { // 還沒有執行刷新,重新隱藏 setHeaderTopMargin(-mHeaderViewHeight); } } break; } return super.onTouchEvent(event); } /** * 是否應該到了父View,即PullToRefreshView滑動 * * @param deltaY * , deltaY > 0 是向下運動,< 0是向上運動 * @return */ private boolean isRefreshViewScroll(int deltaY) { if (mHeaderState == REFRESHING || mFooterState == REFRESHING) { return false; } // 對於ListView和GridView if (mAdapterView != null) { // 子view(ListView or GridView)滑動到最頂端 if (deltaY > 0) { View child = mAdapterView.getChildAt(0); if (child == null) { // 如果mAdapterView中沒有數據,不攔截 return false; } if (mAdapterView.getFirstVisiblePosition() == 0 && child.getTop() == 0) { mPullState = PULL_DOWN_STATE; return true; } int top = child.getTop(); int padding = mAdapterView.getPaddingTop(); if (mAdapterView.getFirstVisiblePosition() == 0 && Math.abs(top - padding) <= 8) {// 這裡之前用3可以判斷,但現在不行,還沒找到原因 mPullState = PULL_DOWN_STATE; return true; } } else if (deltaY < 0) { View lastChild = mAdapterView.getChildAt(mAdapterView .getChildCount() - 1); if (lastChild == null) { // 如果mAdapterView中沒有數據,不攔截 return false; } // 最後一個子view的Bottom小於父View的高度說明mAdapterView的數據沒有填滿父view, // 等於父View的高度說明mAdapterView已經滑動到最後 if (lastChild.getBottom() <= getHeight() && mAdapterView.getLastVisiblePosition() == mAdapterView .getCount() - 1) { mPullState = PULL_UP_STATE; return true; } } } // 對於ScrollView if (mScrollView != null) { // 子scroll view滑動到最頂端 View child = mScrollView.getChildAt(0); if (deltaY > 0 && mScrollView.getScrollY() == 0) { mPullState = PULL_DOWN_STATE; return true; } else if (deltaY < 0 && child.getMeasuredHeight() <= getHeight() + mScrollView.getScrollY()) { mPullState = PULL_UP_STATE; return true; } } return false; } /** * header 准備刷新,手指移動過程,還沒有釋放 * * @param deltaY * ,手指滑動的距離 */ private void headerPrepareToRefresh(int deltaY) { int newTopMargin = changingHeaderViewTopMargin(deltaY); // 當header view的topMargin>=0時,說明已經完全顯示出來了,修改header view 的提示狀態 if (newTopMargin >= 0 && mHeaderState != RELEASE_TO_REFRESH) { mHeaderTextView.setText(R.string.app_name); mHeaderUpdateTextView.setVisibility(View.VISIBLE); mHeaderImageView.clearAnimation(); mHeaderImageView.startAnimation(mFlipAnimation); mHeaderState = RELEASE_TO_REFRESH; } else if (newTopMargin < 0 && newTopMargin > -mHeaderViewHeight) {// 拖動時沒有釋放 mHeaderImageView.clearAnimation(); mHeaderImageView.startAnimation(mFlipAnimation); // mHeaderImageView. mHeaderTextView.setText(R.string.app_name); mHeaderState = PULL_TO_REFRESH; } } /** * footer 准備刷新,手指移動過程,還沒有釋放 移動footer view高度同樣和移動header view * 高度是一樣,都是通過修改header view的topmargin的值來達到 * * @param deltaY * ,手指滑動的距離 */ private void footerPrepareToRefresh(int deltaY) { int newTopMargin = changingHeaderViewTopMargin(deltaY); // 如果header view topMargin 的絕對值大於或等於header + footer 的高度 // 說明footer view 完全顯示出來了,修改footer view 的提示狀態 if (Math.abs(newTopMargin) >= (mHeaderViewHeight + mFooterViewHeight) && mFooterState != RELEASE_TO_REFRESH) { mFooterTextView .setText(R.string.app_name); mFooterImageView.clearAnimation(); mFooterImageView.startAnimation(mFlipAnimation); mFooterState = RELEASE_TO_REFRESH; } else if (Math.abs(newTopMargin) < (mHeaderViewHeight + mFooterViewHeight)) { mFooterImageView.clearAnimation(); mFooterImageView.startAnimation(mFlipAnimation); mFooterTextView.setText(R.string.app_name); mFooterState = PULL_TO_REFRESH; } } /** * 修改Header view top margin的值 * * @param deltaY */ private int changingHeaderViewTopMargin(int deltaY) { LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); float newTopMargin = params.topMargin + deltaY * 0.3f; // 這裡對上拉做一下限制,因為當前上拉後然後不釋放手指直接下拉,會把下拉刷新給觸發了,感謝網友yufengzungzhe的指出 // 表示如果是在上拉後一段距離,然後直接下拉 if (deltaY > 0 && mPullState == PULL_UP_STATE && Math.abs(params.topMargin) <= mHeaderViewHeight) { return params.topMargin; } // 同樣地,對下拉做一下限制,避免出現跟上拉操作時一樣的bug if (deltaY < 0 && mPullState == PULL_DOWN_STATE && Math.abs(params.topMargin) >= mHeaderViewHeight) { return params.topMargin; } params.topMargin = (int) newTopMargin; mHeaderView.setLayoutParams(params); invalidate(); return params.topMargin; } /** * header refreshing * */ private void headerRefreshing() { mHeaderState = REFRESHING; setHeaderTopMargin(0); mHeaderImageView.setVisibility(View.GONE); mHeaderImageView.clearAnimation(); mHeaderImageView.setImageDrawable(null); mHeaderProgressBar.setVisibility(View.VISIBLE); mHeaderTextView.setText(R.string.app_name); if (mOnHeaderRefreshListener != null) { mOnHeaderRefreshListener.onHeaderRefresh(this); } } /** * footer refreshing * */ private void footerRefreshing() { mFooterState = REFRESHING; int top = mHeaderViewHeight + mFooterViewHeight; setHeaderTopMargin(-top); mFooterImageView.setVisibility(View.GONE); mFooterImageView.clearAnimation(); mFooterImageView.setImageDrawable(null); mFooterProgressBar.setVisibility(View.VISIBLE); mFooterTextView .setText(R.string.app_name); if (mOnFooterRefreshListener != null) { mOnFooterRefreshListener.onFooterRefresh(this); } } /** * 設置header view 的topMargin的值 * * @param topMargin * ,為0時,說明header view 剛好完全顯示出來; 為-mHeaderViewHeight時,說明完全隱藏了 */ private void setHeaderTopMargin(int topMargin) { LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); params.topMargin = topMargin; mHeaderView.setLayoutParams(params); invalidate(); } /** * header view 完成更新後恢復初始狀態 * */ public void onHeaderRefreshComplete() { setHeaderTopMargin(-mHeaderViewHeight); mHeaderImageView.setVisibility(View.VISIBLE); mHeaderImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow); mHeaderTextView.setText(R.string.app_name); mHeaderProgressBar.setVisibility(View.GONE); // mHeaderUpdateTextView.setText(""); mHeaderState = PULL_TO_REFRESH; } /** * Resets the list to a normal state after a refresh. * * @param lastUpdated * Last updated at. */ public void onHeaderRefreshComplete(CharSequence lastUpdated) { setLastUpdated(lastUpdated); onHeaderRefreshComplete(); } /** * footer view 完成更新後恢復初始狀態 */ public void onFooterRefreshComplete() { setHeaderTopMargin(-mHeaderViewHeight); mFooterImageView.setVisibility(View.VISIBLE); mFooterImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow_up); mFooterTextView.setText(R.string.app_name); mFooterProgressBar.setVisibility(View.GONE); // mHeaderUpdateTextView.setText(""); mFooterState = PULL_TO_REFRESH; } /** * Set a text to represent when the list was last updated. * * @param lastUpdated * Last updated at. */ public void setLastUpdated(CharSequence lastUpdated) { if (lastUpdated != null) { mHeaderUpdateTextView.setVisibility(View.VISIBLE); mHeaderUpdateTextView.setText(lastUpdated); } else { mHeaderUpdateTextView.setVisibility(View.GONE); } } /** * 獲取當前header view 的topMargin * */ private int getHeaderTopMargin() { LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); return params.topMargin; } // /** // * lock // * // */ // private void lock() { // mLock = true; // } // // /** // * unlock // * // */ // private void unlock() { // mLock = false; // } /** * set headerRefreshListener * * @param headerRefreshListener */ public void setOnHeaderRefreshListener( OnHeaderRefreshListener headerRefreshListener) { mOnHeaderRefreshListener = headerRefreshListener; } public void setOnFooterRefreshListener( OnFooterRefreshListener footerRefreshListener) { mOnFooterRefreshListener = footerRefreshListener; } /** * Interface definition for a callback to be invoked when list/grid footer * view should be refreshed. */ public interface OnFooterRefreshListener { public void onFooterRefresh(PullToRefreshView view); } /** * Interface definition for a callback to be invoked when list/grid header * view should be refreshed. */ public interface OnHeaderRefreshListener { public void onHeaderRefresh(PullToRefreshView view); }}
Android上傳圖片之調用系統拍照和從相冊選擇圖片 Android上傳圖片之調用系統拍照和從相冊選擇圖片 前言: 萬丈高樓平底起,萬事起於微末。不知不覺距離上篇博文已近
RxAndroid使用方法介紹 熟悉RxAndroid的使用方法. 要點包含: (1) 鏈式表達式的使用方式. (2) Lambda的應用. (3) Rx處理網絡請求
淺談android:clipChildren屬性,實現功能: 1、APP主界面底部模塊欄 2、ViewPager一屏多個界面顯示 3、........ 首先
Android學習----自適應國際化語言,android---- 【前言】 自適應的知識與編程無關,關鍵在於配置文件的修改。自適應的內容包括: