如果有時候要隱藏某個物件,但是又是動態隱藏,有時候要打開的話,
該如何做呢?
答案就是使用Visibility!
使用方法十分簡單:
元件類別 元件名稱 = (元件類別)findViewById(R.id.xxx);
元件名稱.setVisibility(VIEW.GONE);
有幾種用法
1.VIEW.VISIBLE(可見,保留位置)
2.VIEW.INVISIBLE(不可見,保留位置)
3.VIEW.GONE(不可見,不保留位置)
這樣一來就可以動態來改變xml裡面的東西囉!
END
2015年2月13日 星期五
2015年2月2日 星期一
[Android] ViewPager的簡易使用方法,Fragment,以及切換分頁監聽實作
之前看一些可以分頁的APP又有動畫,都只是把程式碼抓下來修改一下,就用了.
今天終於稍微搞懂一些裡面的用法.
首先MainActivity.java
1.第一目標 ------ extends FragmentActivity
然後裡面宣告一個PagerAdapter 的變數
2.PagerAdapter宣告的時候一定是出現錯誤,因為你還沒建立一個名為PagerAdapter的型態的
class 所以我們就多建一個java檔名為PagerAdapter 記得要implement FragmentPagerAdapter!
import java.util.List;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
public class PagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
// TODO Auto-generated constructor stub
this.fragments = fragments;
}
@Override
public Fragment getItem(int arg0) {
// TODO Auto-generated method stub
return this.fragments.get(arg0);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return this.fragments.size();
}
}
裡面就是實作他需要的方法(可以按add unimplement method來建立)
3.把PagerAdapter建立起來以後就是要加入分頁了!
在onCreate()裡面新增:
(初始化pager)
private void initialisePaging() {
// TODO Auto-generated method stub
List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, Fragment1.class.getName()));
fragments.add(Fragment.instantiate(this, Fragment2.class.getName()));
mPagerAdapter = new PagerAdapter(this.getSupportFragmentManager(),
fragments);
ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
pager.setAdapter(mPagerAdapter);
myPageChange = new myPageChangeListenter();//new
pager.setOnPageChangeListener(myPageChange);//建立監聽
}
這邊就是建立一個list 然後放進去兩個class(也就是未來的兩個分頁)
當然要在外面宣告兩個變數
private PagerAdapter mPagerAdapter;
public myPageChangeListenter myPageChange;//先宣告一個該型態的變數
不然他會抓不到
--------------------------------------------分隔線------------------------------------------------------
如果到這邊都OK的話,你已經完成一半了.
接下來還要設定監聽(滑動的時候要監聽,不然系統不會去抓你滑到哪一頁了)
我們在上面有用pager.setOnPageChangeListener(myPageChange);來建立監聽
下面當然是要實做這個 myPageChangeListener
public class myPageChangeListenter implements OnPageChangeListener{
@Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
//Log.d("change to page = ",Integer.toString(arg0));
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
//Log.d("scroll to page = ","here");
}
@Override
public void onPageSelected(int arg0) {
// TODO Auto-generated method stub
Log.d("select to page = ",Integer.toString(arg0));
//第一頁為0,第二頁為1
}
}
}
非常簡單,我個人習慣使用onPageSelected來設定動作,都可以透過Log來測試你想要的觸發
--------------------------------------------分隔線------------------------------------------------------
有了 監聽 / PagerAdapter 還需要分頁.....
這部分最大的問題就是在於抓不到該分頁的元件id,當然後來解決了(不然也不會發文)
package com.example.viewpagerexample;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.civetcat.weather.library.WeatherInfo;
import com.civetcat.weather.library.YahooWeather;
import com.civetcat.weather.library.YahooWeather.SEARCH_MODE;
import com.civetcat.weather.library.YahooWeatherInfoListener;
public class Fragment1 extends Fragment implements YahooWeatherInfoListener{
public View view;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
if (container == null) {
return null;
}
view = inflater.inflate(R.layout.fragement1_layout,container, false);
//中間可以使用
TextView txv = (TextView) view.findViewById(R.id.xxx);
//來抓取id
return view;
}
}
Fragment2 也是類似的就不多貼了!
至於layout的部分:
(viewpager_layout.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
這部分是重點!!
看我們這邊在MainActivity.java裡面設定的
setContentView(R.layout.viewpager_layout);
今天終於稍微搞懂一些裡面的用法.
首先MainActivity.java
1.第一目標 ------ extends FragmentActivity
然後裡面宣告一個PagerAdapter 的變數
2.PagerAdapter宣告的時候一定是出現錯誤,因為你還沒建立一個名為PagerAdapter的型態的
class 所以我們就多建一個java檔名為PagerAdapter 記得要implement FragmentPagerAdapter!
import java.util.List;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
public class PagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
// TODO Auto-generated constructor stub
this.fragments = fragments;
}
@Override
public Fragment getItem(int arg0) {
// TODO Auto-generated method stub
return this.fragments.get(arg0);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return this.fragments.size();
}
}
裡面就是實作他需要的方法(可以按add unimplement method來建立)
3.把PagerAdapter建立起來以後就是要加入分頁了!
在onCreate()裡面新增:
(初始化pager)
private void initialisePaging() {
// TODO Auto-generated method stub
List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, Fragment1.class.getName()));
fragments.add(Fragment.instantiate(this, Fragment2.class.getName()));
mPagerAdapter = new PagerAdapter(this.getSupportFragmentManager(),
fragments);
ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
pager.setAdapter(mPagerAdapter);
myPageChange = new myPageChangeListenter();//new
pager.setOnPageChangeListener(myPageChange);//建立監聽
}
這邊就是建立一個list 然後放進去兩個class(也就是未來的兩個分頁)
當然要在外面宣告兩個變數
private PagerAdapter mPagerAdapter;
public myPageChangeListenter myPageChange;//先宣告一個該型態的變數
不然他會抓不到
--------------------------------------------分隔線------------------------------------------------------
如果到這邊都OK的話,你已經完成一半了.
接下來還要設定監聽(滑動的時候要監聽,不然系統不會去抓你滑到哪一頁了)
我們在上面有用pager.setOnPageChangeListener(myPageChange);來建立監聽
下面當然是要實做這個 myPageChangeListener
public class myPageChangeListenter implements OnPageChangeListener{
@Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
//Log.d("change to page = ",Integer.toString(arg0));
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
//Log.d("scroll to page = ","here");
}
@Override
public void onPageSelected(int arg0) {
// TODO Auto-generated method stub
Log.d("select to page = ",Integer.toString(arg0));
//第一頁為0,第二頁為1
}
}
}
非常簡單,我個人習慣使用onPageSelected來設定動作,都可以透過Log來測試你想要的觸發
--------------------------------------------分隔線------------------------------------------------------
有了 監聽 / PagerAdapter 還需要分頁.....
這部分最大的問題就是在於抓不到該分頁的元件id,當然後來解決了(不然也不會發文)
package com.example.viewpagerexample;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.civetcat.weather.library.WeatherInfo;
import com.civetcat.weather.library.YahooWeather;
import com.civetcat.weather.library.YahooWeather.SEARCH_MODE;
import com.civetcat.weather.library.YahooWeatherInfoListener;
public class Fragment1 extends Fragment implements YahooWeatherInfoListener{
public View view;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
if (container == null) {
return null;
}
view = inflater.inflate(R.layout.fragement1_layout,container, false);
//中間可以使用
TextView txv = (TextView) view.findViewById(R.id.xxx);
//來抓取id
return view;
}
}
Fragment2 也是類似的就不多貼了!
至於layout的部分:
(viewpager_layout.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
這部分是重點!!
看我們這邊在MainActivity.java裡面設定的
setContentView(R.layout.viewpager_layout);
因此該xml檔必須要有ViewPager 不然怎麼去抓呢?
大致上就是這樣,把寫了一個天氣的範例放上來,可以參考看看
END
2014年9月5日 星期五
[Android] 儀表板式顯示數值,類Gauge View / 使用Seek Circle 實作
This is a Tutorial about android - like Gauge View or Seek Circle, edit by civetcat.
if you need to do something like meter on UI / Speed meter or anything like that ,
you can just download the zip file,watch the code.
Download Link: SeekCircle-Thread-version // SeekCircle-Normal-version
Original Code : https://github.com/Necat0r/SeekCircle
------------------------------------------------------------------------------------------------------------
以上為給國外朋友參考用。
正文開始:
因為有需要,所以研究了一下如何在Android上面做出一個儀表板型的UI,一開始看了很多國
內的文章幾乎都沒有寫,只有大陸那邊網站稍稍有提到一些,但下載回來都是亂碼,好不容易找到
了一個國外的open-source,於是就下載回來自己修改。
過程當中刪除了一些我覺得不是很必要的code,如果要的話也是可以去原網址這裡下載來
看看,使用方法為用手觸控來調整百分比(要滑動那個圓),看起來滿炫的!但我需要的不是用觸控
型的,所以這邊修改了一下改為你餵數值進去才會動。
第一個版本跟第二個版本其實沒有差很多,只是一個把餵數值的code另外獨立出來做一個thread
而已。
Code這邊可以分為三部分: MainActivity / SeekCircle / ProgressCircle
MainActivity當然就是主程式
/**
* MainActivity.java [V 1.0.0]
* classes :﹛com.caryfish.circleprogress.MainActivity
* 剢豌 create at 2014-8-18 狟敁4:20:40
*/
package com.civetcat.circleprogress;
import com.caryfish.circleprogress.R;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends Activity {
public SeekCircle s_circle;
public static Handler handler;
public sending_thread send_thread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
SeekCircle seekCircle = (SeekCircle) findViewById(R.id.seekCircle);// 建一個seekCircle物件,找id
Log.d("MainActivity", "start...");
try {
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
int[] receive_obj = (int[]) msg.obj; // object無法傳單一int
// 所以用int[]來傳送
updateText(receive_obj[0]);
break;
}
}
};
} catch (Exception e) {
Log.d("Handler exception", e.toString());
}
send_thread = new sending_thread();
send_thread.start();
// **這邊改用Thread.start() 讓他跑,updateText()則用handler去接收來更新資料
}
private void updateText(int input_progress) {
SeekCircle seekCircle = (SeekCircle) findViewById(R.id.seekCircle);
TextView textProgress = (TextView) findViewById(R.id.textProgress);
if (textProgress != null && seekCircle != null) {
seekCircle.setProgress(input_progress);
int progress = seekCircle.getProgress();// 會去ProgressCircle找getProgress()拿資料
textProgress.setText(Integer.toString(progress) + "%");
}
}
}
這邊因為要接收從另個thread來的數據,所以使用handler(請不要使用setText之類的,保證會有錯誤),updateText的部分則是會跑去setProgress(ProgressCircle.java)然後再把set好的數值用getProgress(同樣為ProgressCircle.java)取出來放在text裡面。
這部分應該是最簡單的部分,接下來兩個就是關鍵核心了!
雖然SeekCircle.java看似無用,但也是要他的建構子,所以不能把該檔案刪掉。
package com.civetcat.circleprogress;
import android.content.Context;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
public class SeekCircle extends ProgressCircle
{
/**
* A callback that notifies clients when the progress level has been
* changed. This includes changes that were initiated by the user through a
* touch gesture or arrow key/trackball as well as changes that were
* initiated programmatically.
*/
//SeekCircle建構子,勿刪
public SeekCircle(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
Log.d("SeekCircle","in Seek Circle constructor");
}
public SeekCircle(Context context, AttributeSet attrs)
{
super(context, attrs);
Log.d("SeekCircle","in Seek Circle constructor");
}
public SeekCircle(Context context)
{
super(context);
Log.d("SeekCircle","in Seek Circle constructor");
}
//SeekCircle建構子,勿刪 end
}
這邊能夠調整整個圖形介面的就屬ProgressCircle.java了(MainActivity也是拉...)
package com.civetcat.circleprogress;
import com.caryfish.circleprogress.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
//import com.seekcircle.library.R;
public class ProgressCircle extends View
{
private float mRingBias = 0.15f;
private float mSectionRatio = 5.0f;
private RectF mSectionRect = new RectF();
protected float mSectionHeight;
protected float mRadius;
protected int mMaxProgress;
protected int mProgress;
protected float mCenterX;
protected float mCenterY;
private Paint mPaint;
private int mColor1;
private int mColor2;
private int mInactiveColor;
{
mMaxProgress = 100;
mProgress = 0;
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mColor1 = Color.parseColor("#ffff5900"); //頭端color = 紅
mColor2 = Color.parseColor("#ff33b5e5"); //尾端color = 藍
mInactiveColor = Color.parseColor("#ff404040");
mPaint.setColor(mColor1); // Set default
}
//------建構子
public ProgressCircle(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
initAttributes(context, attrs);
}
public ProgressCircle(Context context, AttributeSet attrs)
{
super(context, attrs);
initAttributes(context, attrs);
}
public ProgressCircle(Context context)
{
super(context);
}
//建構子----end
private void initAttributes(Context context, AttributeSet attrs)
{
TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SeekCircle, 0, 0);
try
{
// Read and clamp max
int max = attributes.getInteger(R.styleable.SeekCircle_max, 100);
mMaxProgress = Math.max(max, 1);
// Read and clamp progress
int progress = attributes.getInteger(R.styleable.SeekCircle_progress, 0);
mProgress = Math.max(Math.min(progress, mMaxProgress), 0);
}
finally
{
attributes.recycle();
}
}
private void updateDimensions(int width, int height)
{
// Update center position
mCenterX = width / 2.0f;
mCenterY = height / 2.0f;
// Find shortest dimension
int diameter = Math.min(width, height);
float outerRadius = diameter / 2;
float sectionHeight = outerRadius * mRingBias;
float sectionWidth = sectionHeight / mSectionRatio;
mRadius = outerRadius - sectionHeight / 2;
mSectionRect.set(-sectionWidth / 2, -sectionHeight / 2, sectionWidth / 2, sectionHeight / 2);
mSectionHeight = sectionHeight;
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (width > height)
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
else
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
updateDimensions(getWidth(), getHeight());
}
@Override //改變size大小
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
updateDimensions(w, h);
}
@Override
protected void onDraw(Canvas canvas)
{
// Center our canvas
canvas.translate(mCenterX, mCenterY);//偏移原本原點多少x,多少y ex:100,100 -> 101,101
float rotation = 360.0f / (float) mMaxProgress; //rotation 旋轉 360/100
for (int i = 0; i < mMaxProgress; ++i)
{
canvas.save();
canvas.rotate((float) i * rotation);
canvas.translate(0, -mRadius);
if (i < mProgress)
{
float bias = (float) i / (float) (mMaxProgress - 1);
int color = interpolateColor(mColor1, mColor2, bias);//漸層顏色
mPaint.setColor(color);//塗上顏色,在這一段
}
else
{
canvas.scale(0.7f, 0.7f);
mPaint.setColor(mInactiveColor);
}
canvas.drawRect(mSectionRect, mPaint);
canvas.restore();
}
super.onDraw(canvas);
}
private float interpolate(float a, float b, float bias) //interpolate = 插值,bias = 偏移,偏差
{
return (a + ((b - a) * bias));
}
private int interpolateColor(int colorA, int colorB, float bias)
{
float[] hsvColorA = new float[3];
Color.colorToHSV(colorA, hsvColorA);
float[] hsvColorB = new float[3];
Color.colorToHSV(colorB, hsvColorB);
hsvColorB[0] = interpolate(hsvColorA[0], hsvColorB[0], bias);
hsvColorB[1] = interpolate(hsvColorA[1], hsvColorB[1], bias);
hsvColorB[2] = interpolate(hsvColorA[2], hsvColorB[2], bias);
// NOTE For some reason the method HSVToColor fail in edit mode. Just use the start color for now
if (isInEditMode())
return colorA;
return Color.HSVToColor(hsvColorB);
}
/**
* Get max progress
*
* @return Max progress
*/
public float getMax()
{
return mMaxProgress;
}
/**
* Set max progress
*
* @param max
*/
public void setMax(int max)
{
int newMax = Math.max(max, 1);
if (newMax != mMaxProgress)
mMaxProgress = newMax;
updateProgress(mProgress);
invalidate();//重新繪製View
}
/**
* Get Progress
*
* @return progress
*/
public int getProgress()
{
Log.d("ProgressCircle","getProgress");
Log.d("ProgressCircle on getProgress,mProgress = ",Integer.toString(mProgress));
return mProgress;
}
/**
* Set progress
*
* @param progress
*/
public void setProgress(int progress)
{
Log.d("ProgressCircle","setProgress");
updateProgress(progress);//設定progress
}
/**
* Update progress internally. Clamp it to a valid range and invalidate the view if necessary
*
* @param progress
* @return true if progress was changed and the view needs an update
*/
protected boolean updateProgress(int progress)
{
Log.d("ProgressCircle","update Progress");
Log.d("ProgressCircle Update Progress,progress = ",Integer.toString(progress));
Log.d("ProgressCircle Update Progress,mProgress = ",Integer.toString(mProgress));
// Clamp progress , clamp = 抓
progress = Math.max(0, Math.min(mMaxProgress, progress));//先跟最大比 如果>100 就取100,再跟0比,最小到0 也就是0~100之間
if (progress != mProgress) //跟目前狀態(mProgress)不同的話
{
mProgress = progress;
invalidate();//重新繪製View
Log.d("ProgressCircle Update Progress,progress = ",Integer.toString(progress));
Log.d("ProgressCircle Update Progress,mProgress = ",Integer.toString(mProgress));
return true;
}
return false;
}
}
原始資料顏色部份是對調的,但我因為讓電池100%時看起來是綠色的,0%時為紅色的,所以就把
數據對調了一下。
值得特別注意的是 progress = Math.max(0, Math.min(mMaxProgress, progress));
//先跟最大比 如果>100 就取100,再跟0比,最小到0 也就是0~100之間
這邊如果要調整最大最小值,可以透過這一行+mMaxProgress來調整。
然後invalidate();則是強制重新繪製view。
最後一塊則是Thread的部分,但thread的部分之前有寫過了,所以就不多加說明了。
其他的部分能研究的都在程式碼裡面有寫註解了,祝大家都可以順利寫出來!
附上載點
訂閱:
文章 (Atom)