0%

Android的动画的使用,请参考。Android的动画,在设计方面,我有点不太理解,觉得这样搞很怪,因为在控件动画后,即使设置了停留在动画结束时的位置,我们也确实看到了控件停在那个位置,但其实该控件的真实位置还是在原来动画前的那里。举个例子,如果有个Button,你给它设置了动画,让它移动到其他位置,当移动完成后,你会发现,点击Button没有任何效果,而在Button原来的位置,就是动画前的位置点击,明明没有任何控件,却看到了点击Button的效果。不知道Google为什么要这样设计。 解决思路:动画不设置结束后停留在结束位置,通过setAnimationListener方法设置动画监听器,在动画结束时,即onAnimationEnd方法中,手动用layout或者setLayoutParams方法把控件移动到动画结束的位置。 范例说明:启动时如下图,一个按钮,按钮上有一条高10像素的白条,其实这是另一个View,但是我把它Y轴设为了负,所以只能看到一部分,另一部分被隐藏在屏幕上方。 按下下拉显示按钮时,那个白色的View会以向下移动,就是下拉动画的效果,显示在屏幕上,如下图: 当点击隐藏后,这个View又会上拉,恢复到第一张图片的样子,显示出原来的下拉显示按钮。 源代码: 布局 main.xml:

<?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" android:layout_height="fill_parent">
    <!-- 因为下面的两个LinearLayout要覆盖,就是显示的位置有重叠,所以,必须使用AbsoluteLayout,绝对布局 -->
    <LinearLayout android:orientation="vertical" android:id="@+id/main"
        android:layout_x="0dp" android:layout_y="0dp" android:layout_width="fill_parent"
        android:layout_height="fill_parent" android:weightSum="1">
        <Button android:layout_width="wrap_content" android:id="@+id/show"
            android:layout_height="wrap_content" android:text="下拉显示" />
    </LinearLayout>
    <LinearLayout android:orientation="vertical" android:id="@+id/selection" 
        android:layout_x="0dp" android:layout_y="-190px" android:layout_width="fill_parent"
        android:layout_height="200px" android:background="@color/white">
        <!-- 之所以用 px作单位,是因为设置控件位置的layout方法的参数就是px单位的,单位相同方便计算
            高200,y座标-190,还有10个像素可以看到,是为了方便演示,当然,你也可以设为-200,刚好全部隐藏
        -->
        <Button android:layout_width="wrap_content" android:id="@+id/hidden"
            android:layout_height="wrap_content" android:text="隐藏" />
    </LinearLayout>
</AbsoluteLayout>

两个描述动画的xml文件,show.xml与hidden.xml: show.xml:

<?xml version="1.0" encoding="utf-8"?>
<set  xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="0"
android:toXDelta="0"
android:fromYDelta="0"
android:toYDelta="190"
android:duration="1000"
 />
 <!-- 座标好像是相对控件的起始位置的,而不是相对父控件 -->
</set>

hidden.xml:

<?xml version="1.0" encoding="utf-8"?>
<set  xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="0"
android:toXDelta="0"
android:fromYDelta="0"
android:toYDelta="-190"
android:duration="1000"
 />
</set>

主程序代码:

package com.test;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Animation.AnimationListener;
import android.widget.AbsoluteLayout;
import android.widget.Button;
import android.widget.LinearLayout;

public class AndroidTestActivity extends Activity
{
    /** Called when the activity is first created. */
    LinearLayout main, selection;
    Button hidden, show;
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        main = (LinearLayout) findViewById(R.id.main);
        selection = (LinearLayout) findViewById(R.id.selection);
        hidden = (Button) findViewById(R.id.hidden);
        show = (Button) findViewById(R.id.show);
        show.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                // TODO Auto-generated method stub
                Animation showAnim=AnimationUtils.loadAnimation(AndroidTestActivity.this, R.anim.show);
//				translate.setFillAfter(true);
                //如果只用setFillAfter方法保存移动后的位置,真实位置不会移动
                selection.startAnimation(showAnim);
                                  //如果下面的View是一个listview,可能需要先执行selection.requestFocusFromTouch();否则第二次不会显示动画
                                 //需要把下面的控件 enable设为false,防止点中下面的控件
                show.setEnabled(false);
                //必须设为false,因为如果连续点击两次,就会连着执行两次移动位置,并不是我们想要的结果
                //等把拉下的view移回去后,再设为true
                showAnim.setAnimationListener(new AnimationListener(){

                    @Override
                    public void onAnimationEnd(Animation animation)
                    {
                        // TODO Auto-generated method stub
                        hidden.setEnabled(true);
                        //当下拉动画结束后,把隐藏的按钮设为可用
                        selection.clearAnimation();
                        selection.layout(selection.getLeft(), 0, selection.getRight(), 200);
//						selection.setLayoutParams(new AbsoluteLayout.LayoutParams(AbsoluteLayout.LayoutParams.FILL_PARENT, 200, 0, 0){});
                        //上面两行功能相同
                        //移动控件到动画结束的位置,clearAnimation方法可以清除动画,屏幕就不会闪,没有的话会闪
                        //setFillAfter不能为true,虽然即使为true,控件真实位置也不会变,但是我们看到的位置是会变的,如果再用layout方法,我们看到的位置还会再变
                        System.out.println(selection.getLeft()+" "+selection.getTop()+" "+selection.getRight()+" "+selection.getBottom());
                        //输出移动后的位置,经过测试,如果不使用layout方法移动控件,动画前,动画后,控件的位置都是不变的
                        //所以,亲眼所见并非真相
                    }
                    @Override
                    public void onAnimationRepeat(Animation animation)
                    {
                        // TODO Auto-generated method stub
                    }
                    @Override
                    public void onAnimationStart(Animation animation)
                    {
                        // TODO Auto-generated method stub
                        System.out.println(selection.getLeft()+" "+selection.getTop()+" "+selection.getRight()+" "+selection.getBottom());
                    }});
            }
        });
        hidden.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View v)
            {
                // TODO Auto-generated method stub
                Animation hiddenAnim=AnimationUtils.loadAnimation(AndroidTestActivity.this, R.anim.hidden);
                selection.startAnimation(hiddenAnim);
                hidden.setEnabled(false);
                hiddenAnim.setAnimationListener(new AnimationListener(){

                    @Override
                    public void onAnimationEnd(Animation animation)
                    {
                        // TODO Auto-generated method stub
                        show.setEnabled(true);
                        selection.clearAnimation();
//						selection.layout(selection.getLeft(), -190, selection.getRight(), 10);
                        selection.setLayoutParams(new AbsoluteLayout.LayoutParams(AbsoluteLayout.LayoutParams.FILL_PARENT, 200, 0, -190){});
                        //以上两行,功能相同
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation)
                    {
                        // TODO Auto-generated method stub
                        
                    }

                    @Override
                    public void onAnimationStart(Animation animation)
                    {
                        // TODO Auto-generated method stub
                        
                    }});
                
                
            }});
        
    }
}

源代码就不传了,基本上都在上面了,除了一个定义白色的strings.xml

网上关于用HttpClient处理重定向的文章很多,但是我测了以后,基本都不能用,因为在我这不管有没重定向,状态码全部返回200,拿到的数据都是重定向后的,就是说HttpClient自动帮我们处理了重定向,可能跟HttpClient的版本有关,我的版本是4.1。 下面是HttpClient 4.1可用的,检测重定向的方法:

        String url = "http://www.javaeye.com/";
        PostMethod postMethod = new PostMethod(url);
        //好像用GetMethod就不行,HttpClient就会自动处理重定向
        HttpClient httpClient = new HttpClient();
        httpClient.getParams().setParameter(HttpMethodParams.USER_AGENT,
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1");// 设置UA
        int statusCode = httpClient.executeMethod(postMethod);
        System.out.println("HTTP状态码:" + statusCode);
        if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY)
        {
            // 从头中取出转向的地址
            Header locationHeader = postMethod.getResponseHeader("location");
            String location = null;
            location = locationHeader.getValue();
            System.out.println("页面重定向到:" + location);
        }

Gallery是个非常强大的控件,但是一般都把它当作显示图片之用。其实只要定制适配器,Gallery可以放进任何控件(显示图片就是放了ImageView)。我本来是想要GridView横向滚动的效果,但是实现起来好像比较麻烦,而Gallery本来就是横向滚动的,只要稍稍修改适配器即可。下面的例子把数据定死了,只需稍稍修改一下,把数据数组作为参数传入即可。 适配器代码:

package com.test;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.TextView;

public class GallleryAdapter extends BaseAdapter
{
     private Context context;  
     String[] s=new String[]{"第一集","第一集","第一集","第一集","第一集","第一集","第一集"};
    @Override
    public int getCount()
    {
        // TODO Auto-generated method stub
        return s.length;
    }
    public GallleryAdapter(Context c) {  
        context = c;  
        
    }  
    @Override
    public Object getItem(int position)
    {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public long getItemId(int position)
    {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
        // TODO Auto-generated method stub
        TextView tv=new TextView(context);
        tv.setText(s[position]);
        tv.setLayoutParams(new Gallery.LayoutParams(120, 120));  
        return tv;
    }
    

}

Activity代码:

package com.test;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Gallery;
import android.widget.TextView;
import android.widget.AdapterView.OnItemSelectedListener;

public class AndroidTestActivity extends Activity {
    /** Called when the activity is first created. */
    Gallery gallery1;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        gallery1=(Gallery)findViewById(R.id.gallery1);
        gallery1.setAdapter(new GallleryAdapter(this));  
        gallery1.setOnItemSelectedListener(new OnItemSelectedListener(){

            @Override
            public void onItemSelected(AdapterView parent, View view, int position, long id)
            {
                // TODO Auto-generated method stub
                //默认情况下,选中或没选中的项,文字颜色都是灰色的,但是被选中的反而要淡一点
                //为了能更突出被选中项,把没选中的设为灰色,选中的设为红色
                Gallery ga=(Gallery)parent;
                for(int i=0;i parent)
            {
                // TODO Auto-generated method stub
                
            }});
    }
}

ListView在更新时报异常: ERROR/AndroidRuntime(15260): java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(2131099657, class android.widget.ListView) with Adapter(class com.pocketdigi.pptheater.ListAdapter)] 应用强制关闭。本来这个异常应该是在新线程中更新ListView,没有发送notifyDataSetChanged()时产生的,但即使用Handler发了,还是会时不时抛异常,这应该是个BUG。 我们可以在Handler里执行notifyDataSetChanged()前,先把ListView隐藏,执行完notifyDataSetChanged()后再显示ListView来处理这个问题:

listView1.setVisibility(View.GONE);
listAdapter.notifyDataSetChanged();
listView1.setVisibility(View.VISIBLE);

不能在新线程里分三次发送Handler消息,必须一次执行 用了上面的方法,可能还会抛异常,那就再稍稍改下代码,把ListView的添加,删除,清空等UI操作都用Handler来处理,方法参考

httpclient.getHttpConnectionManager().getParams().setConnectionTimeout方法不行,因为Android集成的httpclient没这方法

httpclient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 3000);
//连接超时
httpclient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 5000);
//读取超时

在Android中,我们可以用SharedPreferences保存设置,在WP7中,可以用IsolatedStorageSettings。 写入设置:

IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
settings["end_Station"] = textBox2.Text;
settings.Save();//保存
//把textBox2的Text属性用end_Station这个key保存

读取设置:

            object end_Station;
            if (settings.TryGetValue("end_Station", out end_Station))
            {//尝试把key为end_Station的值读到end_Station里,类型为Object,如果读取失败,就返回false,就不会执行下面的语句
             //或者settings.TryGetValue(key,out value),这种形式,读出的直接就是string
                textBox2.Text = (string)end_Station;
            }

有时候,我们只是想用ListBox展示数据,不需要用户选择点击操作,但ListBox并没有isSelectable属性,不能设置是否可选。而默认情况下,当用户点击item时,被点项颜色会变化,这里又不需要这样的颜色变化。 可以通过设置ListBox的SelectionChanged事件来解决这个问题,当选择项改变时,只是不是变成-1,就全部改成-1(即没选)。

        private void listBox1_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
        {
            if(listBox1.SelectedIndex!=-1)
                listBox1.SelectedIndex = -1;
        }

MessageBox会在屏幕顶部显示一个对话框,提示用户选择相应操作。

                MessageBoxResult result = MessageBox.Show("未找到相关车次","提示", MessageBoxButton.OK);
                //前两参数是提示信息,标题
                //按钮类型可以是OK,仅显示“确定”按钮;OKCancel,同时显示“确定”和“取消”按钮。
                if(result.Equals(MessageBoxResult.OK))
                {
                    //判断返回结果
                    NavigationService.GoBack();
                    //回到上一页
                }

抓包需要tcpdump以及Root权限,tcpdump在本文后有下载。 首先把tcpdump传进手机,用adb命令(放SD卡有时会有问题,我一次可以用,但刷了另一个ROM后就不行): adb push tcpdump /data/local/ 然后电脑连接手机,打开CMD,执行: adb shell chmod 6755 /data/local/tcpdump cd /data/local/ ./tcpdump -p -vv -s 0 -w /sdcard/capture.pcap 如果要停止,按ctrl+c。没有root权限会提示no suitable device found 停止后,用WireShark(电脑上的一个抓包工具,自行搜索下载),打开SD卡里的capture.pcap,就可以看到数据包了。 可以用adb pull /sdcard/capture.pcap直接把文件导出到电脑上 tcpdump下载: [download id=”31”]