天气预报中下拉刷新和左右切换

来源:互联网 发布:康师傅 统一 知乎 编辑:程序博客网 时间:2024/04/25 08:06

实现下拉刷新和左右切换,思路比较简单就是在ViewPager中的每个页面中加个下拉刷新ScrollView。但是ViewPager和ScrollView就会有冲突。所有我们要自定义个ViewPager,

import android.content.Context;import android.support.v4.view.ViewPager;import android.util.AttributeSet;import android.view.MotionEvent;/** * 此ViewPager解决与父容器ScrollView冲突的问题,无法完美解决.有卡顿 此自定义组件和下拉刷新scrollview配合暂时小完美,有待改善 *  * @author bavariama *  */public class weatherViewPager extends ViewPager {float x, y;boolean flag;OnSingleTouchListener onSingleTouchListener;public weatherViewPager(Context context) {// TODO Auto-generated constructor stubsuper(context);}public weatherViewPager(Context context, AttributeSet attrs) {// TODO Auto-generated constructor stubsuper(context, attrs);}@Overridepublic boolean onTouchEvent(MotionEvent ev) {if (ev.getAction() == MotionEvent.ACTION_DOWN) {getParent().requestDisallowInterceptTouchEvent(false);if (!flag) {x = ev.getX();y = ev.getY();}} else if (ev.getAction() == MotionEvent.ACTION_MOVE) {if (!flag) {float k = Math.abs((ev.getY()-y) / (ev.getX() - x));getParent().requestDisallowInterceptTouchEvent(ev.getY()<y&&k<1);flag = true;}} else {flag = false;getParent().requestDisallowInterceptTouchEvent(false);}return super.onTouchEvent(ev);}public void onSingleTouch() {if (onSingleTouchListener != null) {onSingleTouchListener.onSingleTouch();}}public interface OnSingleTouchListener {public void onSingleTouch();}public void setOnSingleTouchListner(OnSingleTouchListener onSingleTouchListener) {this.onSingleTouchListener = onSingleTouchListener;}}

下拉刷新自定义View

import android.content.Context;import android.os.AsyncTask;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.ImageView;import android.widget.LinearLayout;import android.widget.ProgressBar;import android.widget.ScrollView;import android.widget.TextView;public class DropLayout extends LinearLayout {private ScrollView sc;private LayoutInflater inflater;private LinearLayout header;private ImageView arrowImg;private ProgressBar headProgress;private TextView lastUpdateTxt;private TextView tipsTxt;private RotateAnimation tipsAnimation;private RotateAnimation reverseAnimation;private int headerHeight; // 头高度private int lastHeaderPadding; // 最后一次调用Move Header的Paddingprivate boolean isBack; // 从Release 转到 pullprivate int headerState = DONE;private RefreshCallBack callBack;private LinearLayout subLayout;static final private int RELEASE_To_REFRESH = 0;static final private int PULL_To_REFRESH = 1;static final private int REFRESHING = 2;static final private int DONE = 3;public DropLayout(Context context, AttributeSet attrs) {super(context, attrs);init(context);}private void init(Context context) {inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);sc = new ScrollView(context);sc.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));// 由于ScrollView 只允许有一个ChildView所以再用LinearLayout来做容器subLayout = new LinearLayout(context);subLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));subLayout.setOrientation(VERTICAL);sc.addView(subLayout);header = (LinearLayout) inflater.inflate(R.layout.drag_drop_header,null);measureView(header);headerHeight = header.getMeasuredHeight();lastHeaderPadding = (-1 * headerHeight); // 最后一次调用Move Header的Paddingheader.setPadding(0, lastHeaderPadding, 0, 0);header.invalidate();this.addView(header, 0);this.addView(sc, 1);headProgress = (ProgressBar) findViewById(R.id.head_progressBar);arrowImg = (ImageView) findViewById(R.id.head_arrowImageView);arrowImg.setMinimumHeight(50);arrowImg.setMinimumWidth(50);tipsTxt = (TextView) findViewById(R.id.head_tipsTextView);lastUpdateTxt = (TextView) findViewById(R.id.head_lastUpdatedTextView);// 箭头转动动画tipsAnimation = new RotateAnimation(0, -180,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);tipsAnimation.setInterpolator(new LinearInterpolator());tipsAnimation.setDuration(200); // 动画持续时间tipsAnimation.setFillAfter(true); // 动画结束后保持动画// 箭头反转动画reverseAnimation = new RotateAnimation(-180, 0,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);reverseAnimation.setInterpolator(new LinearInterpolator());reverseAnimation.setDuration(200);reverseAnimation.setFillAfter(true);// 为scrollview绑定事件sc.setOnTouchListener(new OnTouchListener() {private int beginY;@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_MOVE:if ((sc.getScrollY() == 0 || lastHeaderPadding > (-1 * headerHeight))&& headerState != REFRESHING) {// 拿到滑动的Y轴距离int interval = (int) (event.getY() - beginY);// 是向下滑动而不是向上滑动if (interval > 0) {interval = interval / 2;// 下滑阻力lastHeaderPadding = interval + (-1 * headerHeight);header.setPadding(0, lastHeaderPadding, 0, 0);if (lastHeaderPadding > 0) {// txView.setText("我要刷新咯");headerState = RELEASE_To_REFRESH;// 是否已经更新了UIif (!isBack) {isBack = true; // 到了Release状态,如果往回滑动到了pull则启动动画changeHeaderViewByState();}} else {headerState = PULL_To_REFRESH;changeHeaderViewByState();}}}break;case MotionEvent.ACTION_DOWN:// 加上下滑阻力与实际滑动距离的差(大概值)beginY = (int) ((int) event.getY() + sc.getScrollY() * 1.5);break;case MotionEvent.ACTION_UP:if (headerState != REFRESHING) {switch (headerState) {case DONE:// 什么也不干break;case PULL_To_REFRESH:headerState = DONE;lastHeaderPadding = -1 * headerHeight;header.setPadding(0, lastHeaderPadding, 0, 0);changeHeaderViewByState();break;case RELEASE_To_REFRESH:isBack = false; // 准备开始刷新,此时将不会往回滑动headerState = REFRESHING;changeHeaderViewByState();onRefresh();break;default:break;}}break;}// 如果Header是完全被隐藏的则让ScrollView正常滑动,让事件继续否则的话就阻断事件if (lastHeaderPadding > (-1 * headerHeight)&& headerState != REFRESHING) {return true;} else {return false;}}});}@Overridepublic void addView(View child, int index,android.view.ViewGroup.LayoutParams params) {// 读取XML中的默认给 -1 自己添加的为0 和 1if (index == -1) {subLayout.addView(child, params);return;}super.addView(child, index, params);}//下拉刷新接口public void setRefreshCallBack(RefreshCallBack callBack) {this.callBack = callBack;}private void changeHeaderViewByState() {switch (headerState) {case PULL_To_REFRESH:// 是由RELEASE_To_REFRESH状态转变来的if (isBack) {isBack = false;arrowImg.startAnimation(reverseAnimation);tipsTxt.setText(getResources().getString(R.string.pull_down_to_refresh));}tipsTxt.setText(getResources().getString(R.string.pull_down_to_refresh));break;case RELEASE_To_REFRESH:arrowImg.setVisibility(View.VISIBLE);headProgress.setVisibility(View.GONE);tipsTxt.setVisibility(View.VISIBLE);lastUpdateTxt.setVisibility(View.VISIBLE);arrowImg.clearAnimation();arrowImg.startAnimation(tipsAnimation);tipsTxt.setText(getResources().getString(R.string.loosen_the_refresh));break;case REFRESHING:lastHeaderPadding = 0;header.setPadding(0, lastHeaderPadding, 0, 0);header.invalidate();headProgress.setVisibility(View.VISIBLE);arrowImg.clearAnimation();arrowImg.setVisibility(View.INVISIBLE);tipsTxt.setText(getResources().getString(R.string.refreshing));lastUpdateTxt.setVisibility(View.VISIBLE);break;case DONE:lastHeaderPadding = -1 * headerHeight;header.setPadding(0, lastHeaderPadding, 0, 0);header.invalidate();headProgress.setVisibility(View.GONE);arrowImg.clearAnimation();arrowImg.setVisibility(View.VISIBLE);tipsTxt.setText(getResources().getString(R.string.pull_down_to_refresh));lastUpdateTxt.setVisibility(View.VISIBLE);break;default:break;}}private void onRefresh() {new RefreshAsyncTask().execute();}private class RefreshAsyncTask extends AsyncTask<Void, Void, Void> {protected Void doInBackground(Void... params) {if (callBack != null) {callBack.doInBackground();}return null;}@Overrideprotected void onPostExecute(Void result) {onRefreshComplete();if (callBack != null) {callBack.complete();}}}public interface RefreshCallBack {public void doInBackground();public void complete();}@SuppressWarnings("deprecation")public void onRefreshComplete() {headerState = DONE;lastUpdateTxt.setText(getResources().getString(R.string.the_recently_updated)+ new Date().toLocaleString());changeHeaderViewByState();}// 由于OnCreate里面拿不到header的高度所以需要手动计算private void measureView(View childView) {android.view.ViewGroup.LayoutParams p = childView.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 height = p.height;int childHeightSpec;if (height > 0) {childHeightSpec = MeasureSpec.makeMeasureSpec(height,MeasureSpec.EXACTLY);} else {childHeightSpec = MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);}childView.measure(childWidthSpec, childHeightSpec);}}


由于天气每个页面的布局是一样的,数据不一样。所以我们可以自定义布局在自定义布局类中设置数据

public class WeatherLinearLayout extends LinearLayout {private LayoutInflater inflater;private Context context;private View cityView;private WeatherData tempData;private DropLayout dropLayout;private int index;private WeatherLinearLayout(Context context) {super(context);}public WeatherLinearLayout(Context context, int index) {super(context);this.context = context;this.index = index;inflater = LayoutInflater.from(context);//存储天气数据tempData = WeatherData.getInstance(context);//获取list中的每一页的数据View view = createCityView(tempData.getWidgetEntity(index));addView(view);}//获取城市布局和数据展示private View createCityView(WeatherEntity wEntity) {cityView = inflater.inflate(R.layout.city_weather_data_display, null);findAndSetWeatherView(wEntity, cityView);return cityView;}// 由城市码设置天气情况public void findAndSetWeatherView(WeatherEntity wEntity, View weatherView) {TextView tempText = null;ImageView imageView = null;//下拉刷新控件dropLayout = (DropLayout) weatherView.findViewById(R.id.refreshscrollview);//实现刷新接口dropLayout.setRefreshCallBack(new RefreshCallBack() {@Overridepublic void doInBackground() {//在这里处理具体的刷新内容.............}@Overridepublic void complete() {//判断是否刷新成功if (WeatherData.getInstance(context).getWidgetEntity(index).getCurrentTemp() == null) {Toast.makeText(context,R.string.network_connection_fails_tips,Toast.LENGTH_LONG).show();return;}// 更新数据findAndSetWeatherView(tempData.getWidgetEntity(index), cityView);}});// 发布时间tempText = (TextView) weatherView.findViewById(R.id.cityview_public_time);tempText.setText(wEntity.getObservation_time()+ context.getResources().getString(R.string.update_time));// 日出日落时间tempText = (TextView) weatherView.findViewById(R.id.sunrise);tempText.setText(context.getResources().getString(R.string.sunrise)+ " " + wEntity.getDate0().getSunrise());tempText = (TextView) weatherView.findViewById(R.id.sunset);tempText.setText(context.getResources().getString(R.string.sunset)+ " " + wEntity.getDate0().getSunset()); // 当前温度 tempText = (TextView) weatherView.findViewById(R.id.cityview_temp); tempText.setText(wEntity.getCurrentTemp() + "°");....................}}


布局文件需要注意的已标注

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/weather_background_image"    android:layout_width="fill_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <yong.desk.weather.DropLayout        android:id="@+id/refreshscrollview"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:orientation="vertical" >        <LinearLayout            android:id="@+id/layout_city_view_root"            android:layout_width="fill_parent"            android:layout_height="wrap_content"            android:orientation="vertical" ><!-- 这里一定要用相对布局不然数据展示有问题 -->            <RelativeLayout                android:layout_width="fill_parent"                android:layout_height="wrap_content" >                <TextView                    android:id="@+id/cityview_public_time"                    android:layout_width="wrap_content"                    android:layout_height="wrap_content"                    android:layout_marginLeft="10dip"                    android:textColor="@color/white"                    android:textSize="@dimen/font_size_small" />            </RelativeLayout>            <LinearLayout                android:layout_width="fill_parent"                android:layout_height="100dip" >                                   <TextView                        android:id="@+id/sunrise"                        android:layout_width="wrap_content"                        android:layout_height="wrap_content"                        android:layout_marginLeft="10dip"                        android:text="2015/04/17"                        android:textColor="@color/white"                        android:textSize="@dimen/font_size_big" />                    <TextView                        android:id="@+id/sunset"                        android:layout_width="wrap_content"                        android:layout_height="wrap_content"                        android:layout_marginLeft="10dip"                        android:layout_marginTop="4dip"                        android:textColor="@color/white"                        android:textSize="@dimen/font_size_big" />    <TextView                        android:id="@+id/cityview_temp"                        android:layout_width="wrap_content"                        android:layout_height="wrap_content"                        android:layout_marginLeft="10dip"                        android:layout_marginTop="4dip"                        android:textColor="@color/white"                        android:textSize="@dimen/font_size_big" />              </LinearLayout>                  </LinearLayout>    </yong.desk.weather.DropLayout></LinearLayout>

主活动的调用

public class MainActivity extends Activity implements OnClickListener,OnPageChangeListener {private FrameLayout rootLayout;private weatherViewPager viewPager;private MyAdapter mPagerAdapter;private ArrayList<View> pageViews;private ImageView[] tips;private ImageView cityManager;private TextView cityNameView;private ImageView shareImageView;private ImageView menuImageView;private ViewGroup group;private int position;private long exitTime = 0;private boolean isCityList = true;@Overridepublic void onCreate(Bundle savedInstanceState) {Log.e("MainActivity", "onCreate");super.onCreate(savedInstanceState);setContentView(R.layout.layout_weather_main);initView();// 获取数据getData();}private void initView() {rootLayout = (FrameLayout) findViewById(R.id.frameLayout_main);// 城市管理按钮cityManager = (ImageView) findViewById(R.id.title_city_manager);cityManager.setOnClickListener(this);cityNameView = (TextView) findViewById(R.id.actionbar_city_name);cityNameView.setOnClickListener(this);// 分享按钮shareImageView = (ImageView) findViewById(R.id.title_share);shareImageView.setOnClickListener(this);// meun按钮menuImageView = (ImageView) findViewById(R.id.title_menu);menuImageView.setOnClickListener(this);viewPager = (weatherViewPager) findViewById(R.id.viewPager);//添加标注点group = (ViewGroup) findViewById(R.id.viewGroup);pageViews = new ArrayList<View>();}private void getData() {//获取list中有几页数据tips = new ImageView[WeatherData.getInstance(this).getWidgetEntityListCount()];group.removeAllViews();//添加标注点for (int i = 0; i < tips.length; i++) {ImageView imageView = new ImageView(this);imageView.setLayoutParams(new LayoutParams(10, 10));tips[i] = imageView;if (i == 0) {tips[i].setBackgroundResource(R.drawable.page_indicator_focused);} else {tips[i].setBackgroundResource(R.drawable.page_indicator_unfocused);}LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));layoutParams.leftMargin = 5;layoutParams.rightMargin = 5;group.addView(imageView, layoutParams);}pageViews.clear();//添加数据存储到pageViews<View>的集合中再通过适配器展示for (int i = 0; i < tips.length; i++) {pageViews.add(new WeatherLinearLayout(this, i));}mPagerAdapter = new MyAdapter();viewPager.setAdapter(mPagerAdapter);viewPager.setOnPageChangeListener(this);//指定显示那一页viewPager.setCurrentItem(0);  }@Overridepublic void onClick(View arg0) {Intent intent = null;switch (arg0.getId()) {case R.id.title_city_manager:// 跳转到设置城市的Activitybreak;case R.id.title_city_name:// 跳转到设置城市的Activitybreak;case R.id.title_share://跳转到分享的ActivityString weatherShare = WeatherData.getInstance(this).formatCurWeatherToStirng();if (weatherShare == null) {Toast.makeText(this, R.string.not_set_city_tips,Toast.LENGTH_LONG).show();return;}intent = new Intent(Intent.ACTION_SEND);intent.setType("text/plain");intent.putExtra(Intent.EXTRA_SUBJECT, R.string.share_weather);intent.putExtra(Intent.EXTRA_TEXT, weatherShare);startActivity(Intent.createChooser(intent, getTitle()));break;case R.id.title_menu:// 跳转到帮助的Activitybreak;default:break;}}@Overridepublic void onPageScrollStateChanged(int arg0) {// TODO Auto-generated method stub}@Overridepublic void onPageScrolled(int arg0, float arg1, int arg2) {// TODO Auto-generated method stub}@Overridepublic void onPageSelected(int arg0) {//ViewPager页面变化改变标注点setImageBackground(arg0 % pageViews.size());if (arg0 > pageViews.size() - 1) {return;} else {//设置城市名字WorkspaceProxy.getInstance().changeCityTitle(WeatherData.getInstance(this).getWidgetEntity(arg0).getCityName());}}/** * 设置选中的tip的背景 *  * @param selectItems */private void setImageBackground(int selectItems) {for (int i = 0; i < tips.length; i++) {if (i == selectItems) {tips[i].setBackgroundResource(R.drawable.page_indicator_focused);} else {tips[i].setBackgroundResource(R.drawable.page_indicator_unfocused);}}}//ViewPager适配器public class MyAdapter extends PagerAdapter {@Overridepublic int getCount() {return pageViews.size();}@Overridepublic boolean isViewFromObject(View arg0, Object arg1) {return arg0 == arg1;}@Overridepublic void destroyItem(View container, int position, Object object) {Log.i("jjf", "destroyItem" + position);if (position > pageViews.size() - 1) {return;} else {((ViewPager) container).removeView(pageViews.get(position));}}/** * 载入图片进去,用当前的position 除以 图片数组长度取余数是关键 */@Overridepublic Object instantiateItem(View container, int position) {((ViewPager) container).addView(pageViews.get(position % pageViews.size()), 0);return pageViews.get(position % pageViews.size());}}//按俩下返回退出程序@Overridepublic void onBackPressed() {if ((System.currentTimeMillis() - exitTime) > 2000) {Toast.makeText(getApplicationContext(),getString(R.string.exit_app), Toast.LENGTH_SHORT).show();exitTime = System.currentTimeMillis();} else {finish();System.exit(0);}}}

希望能够帮助大家


0 0